diff --git a/ref-code-adaptation/README.md b/ref-code-adaptation/README.md new file mode 100644 index 00000000..c31089be --- /dev/null +++ b/ref-code-adaptation/README.md @@ -0,0 +1,224 @@ +# ref-code-adaptation + +`ref-code-adaptation` adapts concrete Java code from reference Java code and class-diagram mappings. +## Inputs + +The main entry point is `de.monticore.codeAdaption.CodeAdapter`. + +Required inputs: + +- reference class diagram +- concrete class diagram +- mapping names, such as `buildPat`, `observer`, or `ref` +- adapter/reference Java source directory +- concrete Java source directory +- output directory + +The class diagrams define which reference classes, fields, and methods incarnate as concrete Java elements. Java code is parsed and transformed with MontiCore JavaDSL and Spoon. + +## Adaptation Flow + +1. Load reference and concrete class diagrams with `JavaLoader.parseCD`. +2. Build mapping-specific incarnation contexts. +3. Validate inputs and detect unresolved or ambiguous mappings before creating + a staging workspace or changing existing output. +4. Copy and filter reference adapter code for the active mapping. +5. Adapt types, fields, methods, parameters, constructor calls, and pattern-derived members. +6. Merge adapted code with existing concrete code. +7. Clean generated Java: + - remove `@Adapt` annotations with Spoon + - remove invalid generated imports through JavaDSL import declarations + - preserve valid existing imports without inventing imports for unresolved + simple names + - keep Spoon as the only whole-file formatter; import cleanup edits only + import declaration source ranges +8. Publish the completed staging directory transactionally, restoring the + previous output if publication fails. +9. Compile and structurally verify generated Java in tests. + +The context-building step depends on the `useConcretization` argument of +`CodeAdapter.adapt(...)`. + +### `useConcretization=true` + +This mode delegates model repair to cdconcretization before code adaptation: + +1. `ConcretizationCompleter` completes the concrete CD by adding safe missing + model elements, repairing deterministic inheritance gaps, adapting + multi-incarnation names, and removing redundant inherited attributes. +2. `CDConformanceChecker` validates the completed CD and provides the + mapping-specific incarnation mapping. +3. `JavaTypeUpdateService` projects Java-expressible elements that were added + to the completed concrete CD, such as missing fields, methods, types, enum + constants, inheritance, and interfaces. + +Use this mode when the concrete CD may need deterministic model-level repair +before Java adaptation. + +### `useConcretization=false` + +This mode does not mutate or complete the concrete CD. It builds a manual +incarnation context from: + +- explicit stereotypes for the active mapping name, +- deterministic name and adapted-name rules enabled by `CDConfParameter`, +- manual `<>` mappings derived from already-known + incarnations. + +The manual branch does not call `ConcretizationCompleter` or +`CDConformanceChecker`, and it does not clone or create CD elements. Conflicts +are reported together as a `CodeAdaptationException` before +`JavaLoader.removeDirectory(outputPath)` is executed, so existing output is +preserved when adaptation cannot safely start. + +Supported manual `forEach` targets: + +- Type target: `<> class DataClassBuilder` +- Attribute target: `<> any attribute` +- Owner-implied attribute target: `<> any getAttribute()` + +For method `forEach` over attributes, concrete method incarnations are derived +from already-mapped concrete attributes and deterministic method names, for +example `getAttribute()` to `getFirstName()` and `getAge()`. The manual mode +does not invent cdconcretization suffix rules; concrete stereotypes or enabled +name rules must make the target deterministic. + +## Association Adaptation + +Associations affect Java through navigable role fields. For example, + +```cd +association [1] User -> (roles) Role [*]; +``` + +is generated by the CD4Code configuration as a collection-valued +field comparable to `Set roles` on `User`. `CodeAdapter` and CD4Code have +separate responsibilities: + +- `CodeAdapter` adapts handwritten Java that uses an association. It updates + endpoint type references and owner-scoped direct role-field reads or writes, + such as `this.roles`. +- CD4Code creates the role-derived fields with `--fieldfromrole navigable`. + Association fields are not projected as ordinary CD attributes by + `CodeAdapter`. + +Given `User -> (roles) Role` and the concrete association +`Student -> (roles) HiwiRole`, code such as +`for (Role role : this.roles)` is adapted to use `HiwiRole` while retaining the +role `roles`. If the concrete role is renamed, direct field accesses are renamed +as well. Bidirectional associations are handled per role: a role written on one +association side produces a field on the opposite endpoint, and reads and +assignments are rewritten only inside that owning Java type. + +## Important Implementation Points + +- `JavaLoader.parseCD` must use the same symbol-table setup as `loadCD`, including built-in types. CDs must declare imports explicitly for Java library types such as `Object`, `String`, `List`, or `Optional`. +- `BasicUpdateHandler` handles ordinary and multi-incarnation adaptation through one optional, + immutable stable-key selection. An empty selection represents the ordinary case. +- `MappingAdaptationRunner` owns the isolated per-pass updater lifecycle, output filtering, merge, + cleanup, and error wrapping. +- `CDTypeRelations` centralizes direct generated-AST access for interfaces, + superclasses, modifiers, and type-reference printing. Runtime Java reflection + is not used by the adapter. +- `ManualIncarnationContextBuilder` is the non-mutating context builder for `useConcretization=false`. +- `IncarnationContext` owns one immutable stable-key mapping. MontiCore symbols + are retained only as mapped-element payload for AST operations; symbol object + identity is not used for incarnation lookup. +- `AdaptationConflictDetector` validates manual mappings before Java output is written. +- `JavaTypeUpdateService` fills Java-expressible gaps only after + cdconcretization, such as missing fields, methods, types, enum constants, + inheritance, and interfaces. +- `JavaSourcePostProcessor` is the final source cleanup step. It parses JavaDSL + compilation units for import declarations and removes only known invalid or + malformed generated imports. It does not infer missing JDK imports from + unresolved simple names. +- `JavaSourceNames` centralizes Java/CD type naming, generic rendering, arrays, + primitives, `void`, and `any` normalization. `JavaMethodSignatures` validates + method names and parameter lists through the JavaDSL grammar rather than + splitting them manually; invalid signatures remain unmatched. Callers should + use these utilities instead of open-coded name or signature parsing. +- `SpoonUpdater` is the supported code updater. `RegexUpdater` is preserved + unchanged as deprecated legacy source for compatibility and is outside the + supported adaptation path. +- `CodeUpdaterMill` owns updater initialization and isolation. Use `init()` for + Spoon, `init(Supplier)` for an alternative updater, `getUpdater()` for the + current pass, and `reset()` between isolated passes. +- Generated builder bodies are represented as structured `MethodBodySpec` + values, so setter-return and constructor-return methods are built through + Spoon statements instead of parsed string snippets. +- Concretization compatibility tests inspect and compile the adapter's real output; they do not + substitute a synthetic CD-to-Java projection. +- Concrete handwritten Java packages are authoritative when an adapted top-level type has one + unique same-name concrete declaration. The adapted declaration is merged into that package, and + other adapted units receive imports for types that no longer share their original package. + Multiple concrete package candidates or conflicting imports are rejected instead of guessed. +- The concretization compilation oracle may stub a missing type only when it is declared by the + original concrete CD and one concrete Java package is unambiguous. Types introduced only from the + reference CD are not stubbed, so stale reference names and missing adapter output fail compilation. +- Final generated output must not contain adapter metadata. +- Generated Java cleanup intentionally avoids broad source-text regex formatting. + Comments, literals, generics, operators, and method bodies should be left to + Spoon, JavaDSL, or AST-level code. + + + +## Manual Conflict Detection + +When `useConcretization=false`, the adapter should detect risks that +cdconcretization would otherwise repair or reject on the model level. Reported +conflict categories include: + +- missing used type or `any` type incarnation +- type-kind mismatches that cannot be handled by the selected parent/interface mode +- illegal or ambiguous inheritance situations +- field name/type conflicts and duplicate generated field targets +- duplicate Java method signatures with incompatible return types +- ambiguous overloaded stereotypes without a signature +- enum constant order conflicts +- association-derived Java field conflicts, including cardinality and direction ambiguity +- missing manual `forEach` target incarnations + +`CodeAdapterTestCase1` exercises the `stud` and `prof` mappings together and is +expected to adapt successfully. Association-role conflicts that remain +ambiguous are reported before output generation; the testcase itself is no +longer an error-only scenario. + +## Verification + +The cdconcretization-derived tests use the adapter's generated output as their +oracle input. A correct case means: + +- final Java files exist +- no final Java file contains `@Adapt` or the `Adapt` import +- generated Java compiles +- generated Java structure matches the Java-expressible `*Conc.cd` to `*Out.cd` + completion delta for every type materialized in adapter output, except for the + explicitly registered model boundaries described below + +Exact Java source text is not the main oracle, but generated Java should still be readable and consistently spaced. + +## Current Limitations + +No fixture is hidden in a generic disabled-case bucket. Three underspecified +elements without an incarnation are explicit rollback/error tests: one attribute, +one method parameter, and one method return type. They are invalid because the +placeholder type `any` cannot be emitted into a concrete CD. + +Three fixtures exercise completion semantics that upstream `cdconcretization` +explicitly does not implement. They remain executable rejection/rollback tests: + +- attribute `forEach` across inherited declaring owners +- attribute `forEach` without a target incarnation (requires optional-member or + `matchStructure` semantics) +- method-target `forEach` + +Five fixtures still compile and run, but do not use their complete model as a +structural oracle. Each is registered by path and reason in +`CDConcretizationTestCases`: four mirror tests explicitly disabled upstream +because of unresolved association, binding, cross-incarnation, or bidirectional +`forEach` semantics; the fifth is an inherited attribute-type mismatch that the +current concretizer incorrectly accepts. These cases are not skipped locally; +metadata cleanup and strict Java compilation remain mandatory. + +Fixtures for which upstream provides no separate `*Out.cd` use their reference +CD as the structural oracle, matching the assertions in the upstream tests. diff --git a/ref-code-adaptation/architecture.md b/ref-code-adaptation/architecture.md new file mode 100644 index 00000000..e22bd7d4 --- /dev/null +++ b/ref-code-adaptation/architecture.md @@ -0,0 +1,565 @@ +# ref-code-adaptation Architecture + +This document describes the intended architecture of `ref-code-adaptation`. +It records the module boundaries that keep adapter orchestration, matching, +validation, model analysis, and code rewriting independent from each other. + +The code adapter has one central responsibility: transform handwritten +reference Java code into concrete Java code according to class-diagram +incarnation mappings. The transformation combines two different models: + +- class diagrams, parsed as MontiCore CD ASTs +- Java source code, parsed as JavaDSL ASTs and rewritten through a `CodeUpdater` + +The architecture separates those models from the orchestration flow. A class +that decides which CD element maps to which concrete element does not know how +Spoon renames Java fields. A class that renames Java fields does not know how +manual incarnation conflicts are detected. This separation keeps the adapter +usable with different updater implementations and keeps model-level reasoning +testable without source-rewriting side effects. + +## Layer Overview + +The module is organized into these layers: + +1. **Entry and orchestration** + Coordinates one adaptation run from input files to output files. + +2. **Model loading and indexing** + Parses CD and Java sources and exposes precomputed CD relationships. + +3. **Mapping and matching** + Interprets adapter annotations, stereotypes, name rules, and incarnation + contexts. + +4. **Validation and conflict detection** + Checks whether an adaptation run is deterministic before a staging + workspace is created or existing output is changed. + +5. **Adaptation handlers** + Convert mapping decisions into updater operations for Java AST elements. + +6. **Updater facade and updater implementations** + Apply source-code changes through Spoon or another implementation. + +7. **Post-processing and verification helpers** + Clean generated Java and support tests with structural oracles. + +The allowed dependency direction is top-down: + +```text +CodeAdapter + -> context builders / validators / handlers / output merger + -> matchers / CD indexes / Java collectors / updater interface + -> concrete updater implementation +``` + +Concrete updater code stays behind the `CodeUpdater` interface. Handler and +orchestration code talks to `CodeUpdater`, not to Spoon. + +## Packages + +### `de.monticore.codeAdaption` + +This package contains the public entry point and CLI wrapper. + +- `CodeAdapter` is the API entry point for Java adaptation. +- `CodeAdapterTool` is the CLI integration. +- `CodeAdaptationException` is the user-facing failure type for deterministic + adaptation conflicts. +- `AdaptedCodeMerger` owns Java AST filtering, splitting, deduplication, and + merging after isolated mapping runs. +- `OutputCodeService` owns final generated-source cleanup and concrete + handwritten-file inclusion. +- `AdaptationWorkspace` owns normalized path validation, safe temporary + directories, rollback, and transactional output publication. + +The entry package coordinates the workflow. It owns high-level sequencing: + +- parse reference and concrete CDs +- delegate optional concrete-CD completion to the context layer +- delegate incarnation context construction to the context layer +- validate mappings before destructive output changes +- run one or more mapping adaptation passes +- merge adapted Java with concrete handwritten Java through `AdaptedCodeMerger` +- invoke final cleanup and concrete file copying through `OutputCodeService` + +The entry package does not own low-level rewriting. It delegates Java changes to +`CodeUpdater`, mapping lookups to context builders and validators, and CD +relationship lookups to `CDModelIndex`. + +`CodeAdapter` plans mapping passes with immutable stable-key selections and accumulates their +results. `MappingAdaptationRunner` owns the complete isolated pass operation: cloning reference +Java ASTs, temporary mapping directories, updater initialization, handler execution, output +filtering, merge, cleanup, and error wrapping. + +#### `AdaptedCodeMerger` + +`AdaptedCodeMerger` is package-private because it is part of the orchestration +implementation, not the public API. It owns all Java compilation-unit decisions +that happen after a handler has produced adapted code: + +- `filterCodeForMapping(...)` keeps only Java units relevant for the current + mapping or explicitly ignored by adapter metadata. +- `splitCompilationUnitsByType(...)` turns one JavaDSL compilation unit with + multiple top-level types into one unit per top-level type, preserving package + declarations and assigning a source file name per generated type. +- `mergeAdaptedCode(...)` accumulates generated units from several mappings and + merges same-file units through `AdapterUtils.mergeAsts(...)`. +- `mergeAdaptedCodeIntoConcreteBase(...)` overlays adapted pattern code on top + of concrete handwritten Java and filters out reference-only template artifacts. When a unique + same-name concrete declaration moves an adapted type into another package, the merger reconciles + imports in dependent adapted units before changing package identity. Ambiguous concrete packages + and conflicting simple-name imports are rejected. +- `deduplicateBySimpleName(...)` keeps one unit per simple file name, preferring + the unit with the deeper package-relative path. + +This class depends on JavaDSL AST traversal, `CodeValidator`, +`IncarnationContext`, `AdapterUtils`, `CDModelIndex`, and `JavaSourceNames`. +It does not create updaters, run conformance checks, or write files. + +#### `OutputCodeService` + +`OutputCodeService` is package-private and owns the final filesystem-facing +operations after Java AST generation: + +- `cleanCode(...)` creates a fresh updater and delegates implementation-specific + cleanup to `CodeUpdater.cleanCode(...)`. +- `copyConcreteFiles(...)` includes concrete handwritten files that were not + already produced by adaptation. +- `concreteCopyTarget(...)` preserves package-based Java output paths when a + concrete Java file parses successfully. Non-Java files preserve their original + relative paths. Unparsable concrete Java is rejected because its authoritative + package identity cannot be determined safely. + +This class keeps file-copying and cleanup out of `CodeAdapter`. It does not +inspect adaptation mappings and does not merge ASTs. + +### `de.monticore.codeAdaption.context` + +The context package contains services that prepare model-level adaptation +context before Java rewriting starts. + +- `MappingConformanceService` creates `CDConformanceChecker` instances and runs + conformance checks with the adapter's fail-quick handling. +- `ConcretizationService` wraps `ConcretizationCompleter` and owns the + concretization-mode fail-quick policy. +- `AdaptationContextFactory` builds one `IncarnationContext` per mapping. It + uses manual contexts directly in manual mode and chooses conformance-derived + or stereotype-derived contexts in concretization mode. +- `GroupingMappingService` computes concrete-type-simple-name to + grouping-type-simple-name replacements for one mapping context, preventing + grouping decisions from leaking between mappings. + +This package operates on CD ASTs, conformance checkers, and incarnation +contexts. It does not parse Java code, create updater instances, or mutate the +output directory. + +The context package is the boundary between model-level preparation and +Java-level adaptation. Manual mode and concretization mode meet here: both +produce the same `Map` shape for later workflow +phases. + +### `de.monticore.codeAdaption.matcher` + +Matchers translate annotation and naming information into `CodeMatching` +objects. They answer the question: + +```text +Which reference CD element(s) does this Java AST element represent? +``` + +Important matcher groups: + +- annotation matchers read explicit `@Adapt` metadata +- name matchers use same-name relationships +- infix matchers support generated names that contain the reference name +- composition matchers combine multiple matching strategies +- ignore and error matchers encode non-adapted and invalid cases + +Matchers do not mutate Java code. They produce mapping information consumed by +validators and handlers. + +### `de.monticore.codeAdaption.validator` + +`CodeValidator` owns Java-side validation and exposes matched elements to the +handlers. It initializes matchers for the current Java AST set and provides +queries such as: + +- matched type for a Java type declaration +- matched field for a Java field declaration +- matched method for a Java method declaration +- matched local variable or method parameter +- matched supertype usage + +Validator classes and CoCos check adapter annotation syntax and semantic +validity. They do not write output files and do not use Spoon. + +### `de.monticore.codeAdaption.handler` + +Handlers convert validated mapping information into updater operations. + +`BasicUpdateHandler` handles both ordinary and multi-incarnation passes. Its optional immutable +selection maps stable reference keys to mapped concrete elements; the empty selection is the +ordinary case. It coordinates three coarse-grained collaborators: `ConcreteSymbolResolver` +resolves stable pass selections, concrete symbols, and method signatures, +`JavaMemberUpdateService` owns variables, members, supertypes, and association-role rewrites, and +`JavaTypeUpdateService` owns type renaming, generation, and completed-CD member projection. The +handler is final and exposes no subclass variation points; its package-local forwarding methods +exist only for those collaborators. + +Handlers are the bridge between model reasoning and Java rewriting. They know +both CD concepts and Java AST concepts, but they still depend only on the +updater interface. + +### `de.monticore.codeAdaption.handler.multiIncarnation` + +This package owns incarnation context construction, selection, and manual +conflict detection. + +Core concepts: + +- `StableElementKey` is the stable, model-independent key for types, fields, + methods, and enum constants. +- `IncarnationContext` is the single immutable source of truth for one mapping. + It maps stable reference keys to `MappedElement` values containing the stable + concrete key and the concrete symbol needed by AST operations. Symbols are + payload and never lookup keys. +- `IncarnationContextBuilder` builds contexts from cdconcretization results and + stereotype overlays. +- `ManualIncarnationContextBuilder` builds contexts without mutating or + completing the concrete CD. +- `AdaptationConflictDetector` validates manual mappings before output is + removed. It is a facade over `AdaptationConflictCheck` strategies in the + `handler.multiIncarnation.conflict` package. +- adaptation passes select concrete types by stable key; member selection is derived directly from + the selected stable concrete owner. + +This package operates on CD ASTs and symbols. It does not read or write Java +source files. + +#### Conflict Checks + +Manual conflict detection is strategy-based. `ConflictDetectionContext` owns +the read-only model indexes, mapping names, incarnation contexts, conformance +parameters, type maps, and common-parent flag. `ConflictCollector` owns message +formatting and deterministic sorting. + +The default registry `DefaultConflictChecks` runs these checks: + +- `ManualMappingConflictCheck` for explicit type, field, and method mapping + conflicts. +- `ConcreteTypeStructureConflictCheck` for invalid inheritance shapes and + inheritance cycles. +- `ConcreteMemberConflictCheck` for duplicate concrete members and inherited + field conflicts. +- `EnumConflictCheck` for enum constant order conflicts. +- `AssociationConflictCheck` for association direction, cardinality, and role + field conflicts. +- `UnderspecifiedTypeConflictCheck` for unresolved `any` types in manual mode. +- `AmbiguousStereotypeConflictCheck` for overloaded method stereotypes without + signatures. +- `ForEachConflictCheck` for `forEach` declarations without concrete + incarnations. + +`AdaptationConflictDetector` exposes one static validation path over this fixed built-in set. +Test-only injection of additional checks is not part of the production API. + +### `de.monticore.codeAdaption.updater` + +The updater package defines Java source-rewriting capabilities. + +`CodeUpdater` is the facade used by orchestration and handlers. It contains the +operations the rest of the adapter needs: + +- rename Java types, fields, methods, variables, parameters, and supertypes +- update CD-only type references +- register owner-aware method rewrites and concrete invocation signatures +- add or remove fields, methods, and generated types through one field-generation operation and one + structured `MethodBodySpec` method-generation operation +- write the current Java model +- clean generated source code + +The interface is intentionally broader than simple renaming because cdconcretization and template +expansion create Java elements that were not present in the reference code. It contains only +capabilities used by production orchestration and handlers. Spoon decides internally whether a +generated method must remain signature-only; that implementation detail is not part of the updater +contract. Unsupported defaults remain only where the protected `RegexUpdater` compatibility class +cannot implement Spoon-backed generation behavior. + +`CodeUpdaterMill` owns one synchronized updater provider and one current updater +instance. `init()` restores Spoon, `init(Supplier)` configures an interchangeable +implementation, `getUpdater()` lazily creates the updater for one pass, and +`reset()` discards that instance while retaining its provider. +`MappingAdaptationRunner` and `OutputCodeService` own exception-safe reset +boundaries for isolated passes and final cleanup respectively. + +### `de.monticore.codeAdaption.updater.spoonUpdater` + +`SpoonUpdater` is the supported updater implementation. It parses Java files +with Spoon, maps MontiCore Java AST elements to Spoon elements, applies +refactorings, creates missing members, and prints generated Java. + +Spoon-specific responsibilities stay in this package: + +- Spoon model setup and output +- Spoon refactoring calls +- Spoon type-reference creation +- Spoon method-body construction +- Spoon cleanup of adapter annotations + +`SpoonUpdater` is a facade over four coarse-grained collaborators: + +- `SpoonWorkspace` owns model/factory lifecycle, printing, cleanup, and shared + type-reference construction. +- `SpoonTransformationService` owns declaration and variable renames, grouping, and + type-reference mutations. It uses the workspace's type-reference factory but owns replacement + policy because replacement changes an existing model. +- `SpoonExecutableRepairService` owns invocation renames, overload-aware method rewrites, + concrete signature repair, and interface executable validity. +- `SpoonGenerationService` owns type/member creation, method bodies, and removal. + +`SpoonElementResolver` owns JavaDSL-to-Spoon element lookup and resets its caches +when a new workspace is loaded. The transformation and executable-repair services share the same +workspace and resolver instances. Grouping/type transformations run before executable repair, and +the grouping map is passed read-only for that repair pass rather than cached twice. The facade +keeps its public compatibility wrappers. + +Other packages do not import `spoon.reflect.*`. + +### `de.monticore.codeAdaption.updater.regexUpdater` + +`RegexUpdater` is protected deprecated legacy source. It remains outside the +main architecture path and is preserved unchanged for source compatibility; +its historical text replacement is not a supported updater implementation. +New production code uses `SpoonUpdater` through `CodeUpdater`. + +### `de.monticore.codeAdaption.utils` + +Utility classes provide shared infrastructure: + +- `JavaLoader` parses and prints Java/CD inputs. +- `CDModelIndex` precomputes CD type, member, owner, inheritance, and + association relationships. +- `CDTypeRelations` centralizes direct access to CD type relationships. +- `JavaSourceNames` centralizes Java/CD type rendering, signature keys, simple + names, generics, arrays, primitives, and `any` normalization. +- `JavaMethodSignatures` validates method lookup keys with JavaDSL. Parameter + lists are represented as one synthetic generic type so the grammar, not + comma/depth string logic, decides whether they are valid. +- `JavaSourcePostProcessor` performs final import cleanup. +- `AdapterUtils` contains AST merge and file-name helpers. + +Utilities are shared only when they are stable and domain-neutral. New behavior +that belongs to a specific phase belongs in the package for that phase, not in +`utils`. + +### `de.monticore.codeAdaption.utils.visitors` + +Visitors collect Java AST elements and remove adapter metadata. They provide +small traversal helpers rather than adaptation decisions. + +`JavaAstElemCollector` gives handlers stable access to type declarations, +fields, methods, local variables, parameters, and supertypes in one Java +compilation unit. + +## Runtime Adaptation Flow + +The main workflow has these phases: + +1. `CodeAdapter` parses the concrete and reference CDs through `JavaLoader`. +2. The reference CD and original concrete CD receive immutable indexes. In + concretization mode, `ConcretizationService` completes a cloned concrete CD + once for all mappings and publishes the clone only after success. In manual + mode, the concrete CD remains unchanged. +3. The completed concrete CD receives one immutable index. The reference and + completed indexes are reused by context construction and every Java + adaptation pass; the original concrete index remains available only for + pre-completion decisions. +4. `AdaptationContextFactory` builds one incarnation context for each mapping. +5. Manual mode and any stereotype-derived concretization fallback run + `AdaptationConflictDetector` before staging or output publication begins. +6. `GroupingMappingService` computes common-parent grouping replacements when + common-parent adaptation is enabled. +7. `CodeAdapter` creates conformance checkers and Java validators for each + mapping. +8. `AdaptationWorkspace` creates an isolated staging directory only after all + preflight checks succeed. +9. Reference Java source is parsed into JavaDSL ASTs. +10. `CodeAdapter` plans zero, one, or many isolated passes using immutable stable-key selections; + the ordinary case is one pass with an empty selection. +11. `AdaptedCodeMerger.filterCodeForMapping(...)` keeps the Java units relevant + to the active mapping. +12. `MappingAdaptationRunner` configures one `BasicUpdateHandler` for the pass and runs the updater + lifecycle in a temporary output directory. +13. `AdaptedCodeMerger.splitCompilationUnitsByType(...)` gives generated + top-level types separate Java units. +14. `AdaptedCodeMerger.mergeAdaptedCode(...)` accumulates results from all + mapping passes. +15. `AdaptedCodeMerger.mergeAdaptedCodeIntoConcreteBase(...)` overlays adapted + Java on concrete handwritten Java. +16. `OutputCodeService.cleanCode(...)` removes adapter annotations and invalid + generated imports in staging. +17. `OutputCodeService.copyConcreteFiles(...)` copies remaining concrete + handwritten files into staging. +18. `AdaptationWorkspace` atomically publishes staging and restores the prior + output on publication failure. + +The workflow protects user output by performing conflict detection before +staging and replacing output only after every mapping and cleanup phase +succeeds. + +## Manual Mode and Concretization Mode + +The adapter supports two modes. + +### Manual Mode + +Manual mode uses stereotypes, deterministic name rules, and manual `forEach` +rules. It does not call cdconcretization and does not mutate the concrete CD. + +Manual mode requires strict conflict detection because there is no model-level +repair phase. `AdaptationConflictDetector` reports ambiguous or unsafe cases +before output files are touched. + +### Concretization Mode + +Concretization mode calls `ConcretizationCompleter` before code adaptation. +`ConcretizationService` owns this call and the fail-quick handling around it. +It rebuilds the completed clone's symbol table after mutation so later indexes, +conformance checks, and contexts observe added model elements. +After completion, `AdaptationContextFactory` uses conformance mappings when +available and falls back to manual stereotype-derived contexts when conformance +information is missing. Such fallback mappings discard the failed checker and +must pass the same conflict detector as manual mode before staging. + +Completed-CD projection is part of `JavaTypeUpdateService`. It writes +Java-expressible elements introduced by the completed CD into generated Java +while sharing generated-type tracking and template-member handling with the +rest of type generation. + +## Clean Layer Boundaries + +The following dependency rules keep the layers separated: + +- `CodeAdapter` coordinates phases but does not inspect individual Java members + for renaming details. +- `CodeAdapter` delegates context construction, grouping-map calculation, + adapted-code merging, output cleanup, and concrete-file copying to dedicated + collaborators. +- `BasicUpdateHandler` calls `CodeUpdater` but does not import Spoon. +- `JavaMemberUpdateService` owns both ordinary member changes and + association-derived role field rewrites so their target-detection and + exclusion rules stay together. +- `CodeUpdater` does not know how incarnation contexts are built. +- `SpoonUpdater` does not parse CD mappings or call matchers. +- `AdaptationConflictDetector` reports model conflicts but does not clean, + copy, or print Java files. +- `CDModelIndex` exposes model relationships and avoids repeated full-CD scans + throughout adaptation logic. +- `JavaSourceNames` owns string rendering of names and types, while + `JavaMethodSignatures` owns signature lookup keys. Open-coded signature + parsing or generic type printing stays out of handlers and validators. + Malformed signature text is not partially normalized into a potentially + valid lookup key. +- `CDTypeRelations` uses direct CD AST APIs for type relationships; runtime + reflection is not part of normal adaptation logic. + +## R-017 Refactoring State + +Requirement R-017 reduces oversized classes by responsibility, not by arbitrary +line slicing. The current refactoring state is: + +| Class | Current role | Current state | +| --- | --- | --- | +| `CodeAdapter` | Public API, pass planning, and adaptation-run orchestration | Context creation, grouping maps, merge logic, cleanup, concrete file copying, and isolated pass execution have dedicated collaborators. It is 543 physical lines after pass execution moved to `MappingAdaptationRunner`; pass calculation remains close to orchestration. | +| `MappingAdaptationRunner` | Isolated mapping-pass execution | Package-private runner for clone, print, updater/handler lifecycle, output filtering, merge, cleanup, and wrapped diagnostics. | +| `AdaptedCodeMerger` | Java AST filtering, splitting, deduplication, and merge policy | Extracted from `CodeAdapter`; package-private orchestration helper. | +| `OutputCodeService` | Final cleanup and concrete handwritten-file inclusion | Extracted from `CodeAdapter`; package-private orchestration helper. | +| `AdaptationContextFactory` | Mapping-to-context construction for manual and concretization modes | Extracted into `de.monticore.codeAdaption.context`. | +| `MappingConformanceService` | Safe conformance checker creation and execution | Extracted into `de.monticore.codeAdaption.context`. | +| `ConcretizationService` | Concrete CD completion and fail-quick handling | Extracted into `de.monticore.codeAdaption.context`. | +| `GroupingMappingService` | Mapping-local concrete-to-grouping replacement map with conflict rejection | Extracted into `de.monticore.codeAdaption.context`. | +| `BasicUpdateHandler` | Unified handler pipeline coordinator | About 160 lines. Accepts an optional immutable stable-key selection, delegates resolution/member/type changes, and has no compatibility constructors or subclass hooks. | +| `AdaptationConflictDetector` | Manual-mode model conflict aggregation | A roughly 60-line static facade over the built-in `AdaptationConflictCheck` strategies under `handler.multiIncarnation.conflict`. | +| `SpoonElementResolver` | JavaDSL-to-Spoon declaration lookup and caches | Extracted from `SpoonUpdater`; owns type/method matching and cloned-type cache registration. | +| `SpoonUpdater` | Concrete `CodeUpdater` facade backed by Spoon | About 184 lines after generation overloads were consolidated. Delegates to the workspace, transformation, generation, and element-resolution collaborators. | +| `SpoonTransformationService` | Spoon declaration/variable renames, grouping rewrites, and type-reference transformations | About 376 lines after executable repair was separated. It retains the lazy type-reference indexes and resolved-library safeguards. | +| `SpoonExecutableRepairService` | Invocation and concrete-signature repair | About 300 lines. It shares the workspace/resolver, treats resolved overload declarations as authoritative, and owns no duplicate type or grouping cache. | +| `IncarnationContext` | Immutable stable-key incarnation and grouping lookup | About 70 lines. Owns the only runtime incarnation representation; MontiCore symbols are mapped-element payload only. | +| `IncarnationContextBuilder` | Conformance mappings with optional stereotype overlay | About 140 lines. Populates the stable-key context directly through `IncarnationMappingSupport`. | +| `ManualIncarnationContextBuilder` | Non-mutating manual and `forEach` mapping construction | About 240 lines. Uses stable-key lookups throughout, including `forEach` expansion. | +| `IncarnationMappingSupport` | Shared stable-key mapping, stereotype, reference-index, and grouping infrastructure | About 380 lines. It builds one canonical map and one immutable implementer-to-grouping index; it has no symbol-identity registry. | + +Most production Java classes are below the 500-physical-line target. R-017 remains +open because `CodeAdapter` is the known deferred exception; its next split should +follow the responsibilities described above. `CodeAdapter` and the updater +mill retain their documented entry points. Handler, context-builder, and conflict-detector helpers +are internal implementation surfaces and retain only production-used entry points. The +concretization oracle compares Java-expressible completion deltas from the +original `*Conc.cd` to `*Out.cd` for materialized adapter types and compiles +actual adapter output rather than generating a synthetic substitute. Golden +models that depend on completion behavior absent from the current upstream +dependency, or that cannot describe valid concrete Java, are registered with a +fixture-specific reason; those cases still pass the strict compilation oracle. + +## Data Ownership + +### CD ASTs + +Reference and concrete CD ASTs are owned by the adaptation run. In manual mode, +both ASTs are read-only after parsing. In concretization mode, the concrete CD +is completed before indexing and adaptation. + +### Incarnation Contexts + +An `IncarnationContext` belongs to one mapping. Stable reference keys map to +immutable lists of mapped concrete elements. Each mapped element retains its +stable key and MontiCore symbol, but symbols never participate in identity or +fallback lookup. An adaptation pass optionally selects mapped elements with another immutable +stable-key map. A single immutable implementer-to-grouping index supports common-parent handling. + +### Java ASTs + +`CodeAdapter` parses reference Java into JavaDSL ASTs. Each isolated mapping +pass works on a deep clone of those ASTs. The `CodeUpdater` implementation owns +the source model it rewrites and prints. + +### Output Files + +Temporary mapping directories and the final merged output live in an isolated +staging workspace. Existing output remains untouched until successful +transactional publication. + +## Error Handling + +Conflict detection errors are aggregated into `CodeAdaptationException` so users +receive all manual-mode problems at once. + +Conformance and concretization failures are logged and converted into fallback +paths where deterministic manual mapping information exists. Fallback behavior +does not hide ambiguity; unsafe cases are still rejected by conflict detection. + +Updater errors indicate source-rewriting failures and are allowed to fail the +current adaptation pass. + +## Testing Architecture + +The test suite uses several verification levels: + +- adaptation tests assert generated files and compile generated Java +- cdconcretization-derived tests compare materialized generated Java structure + against the expected `*Conc.cd` to `*Out.cd` completion delta, with every + non-applicable golden model registered with an explicit reason +- conflict detector tests assert deterministic diagnostics for unsafe manual + cases +- updater behavior is covered through end-to-end adaptation scenarios + +The concretization compilation oracle treats the original concrete CD as the boundary for +external generated dependencies. It prefers real adapted and handwritten Java sources and creates +a minimal stub only for an original concrete-CD type in one unambiguous concrete package. It never +completes the stub set from the reference CD. This makes stale reference types, wrong packages, and +missing adapter-generated types visible as compilation failures. + +Structural verification is preferred over exact source text comparison. Source +formatting remains the responsibility of Spoon and final post-processing. diff --git a/ref-code-adaptation/evaluation.md b/ref-code-adaptation/evaluation.md new file mode 100644 index 00000000..f0643c66 --- /dev/null +++ b/ref-code-adaptation/evaluation.md @@ -0,0 +1,31 @@ +# Ref-Code-Adaptation Evaluation Cases + +This document describes the numbered evaluation resources under +`src/test/resources/de/monticore/codeAdaption/evaluation`. Each case contains a +reference CD, a concrete CD, and either adapter handwritten code, concrete +handwritten code, or both. + +## Case Overview + +| Case | Purpose | Inputs | Mappings | Expected behavior | Test coverage | +| --- | --- | --- | --- | --- | --- | +| `testcase_1` | University/user-role case with two mappings over shared concrete types. | `Reference.cd`, `Concrete.cd`, `reference/` | `stud`, `prof` | Adapts both mappings successfully. The former association-role conflict is resolved by treating roles as generated fields owned by the opposite association side. | `CodeAdapterTestCase1` | +| `testcase_2_cd4code` | CD4Code user-role case with generated follow-up code. | `Reference.cd`, `Concrete.cd`, `hwc/` | `stud` | Adapts the reference handwritten code to `Student`/`HiwiRole` and then runs Java generation for the concrete CD. | `CodeAdapterTestCase2a` | +| `testcase_6_builder_pattern` | Builder pattern expansion for multiple concrete target types. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `buildPat` | Creates `PersonBuilder` and `TaskBuilder`, adapts setters/build methods, and keeps existing concrete classes. | `BuilderPatternAdapterTest` | +| `testcase_7_controller_worker_observer` | Combined builder and observer adaptation where workers are observers. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `buildPat`, `observer` | Generates/adapts controller and worker builder/observer code while preserving concrete worker classes. | `ControllerWorkerAdapterTest` | +| `testcase_8_controller_worker_observer_reversed` | Variant of controller/worker observer adaptation with reversed observer modelling. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `buildPat`, `observer` | Adapts the same pattern combination when the observer interface/class relation is represented differently. | `ControllerWorkerAdapterReversedTest` | +| `testcase_9_strategy_pattern` | Strategy pattern adaptation. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `strategy` | Adapts context and strategy types/methods to payment processing classes and strategies. | `StrategyAdapterTest` | +| `testcase_10_singleton_pattern` | Singleton pattern adaptation for multiple concrete singleton classes. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `singleton` | Produces singleton-style code for `DatabaseConnection` and `Logger` and preserves the application code. | `SingletonAdapterTest` | +| `testcase_11_template_method_pattern` | Template method adaptation with several concrete processors. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `template` | Adapts the abstract template and concrete processor methods for CSV, JSON, and XML processors. | `TemplateMethodAdapterTest` | +| `testcase_12_strategy_singleton_pattern` | Combined singleton and strategy adaptation. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `singleton`, `strategy` | Adapts configuration manager singleton behavior and storage strategy variants. | `StrategySingletonAdapterTest` | +| `testcase_13_template_observer_pattern` | Combined template method and observer adaptation. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `template`, `observer` | Adapts data pipeline template methods and observer notification/update code. | `TemplateObserverAdapterTest` | +| `testcase_14_adapter_factory_combined` | Combined adapter and factory pattern resource case. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `adapter`, `factory` | Adapts a shipping port/carrier adapter with factory creation. | `CombinedPatternEvaluationTest` | +| `testcase_15_composite_decorator_combined` | Combined composite and decorator pattern resource case. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `composite`, `decorator` | Adapts renderable components, groups, and decorators. | `CombinedPatternEvaluationTest` | +| `testcase_16_observer_command_combined` | Combined observer and command pattern resource case. | `Reference.cd`, `Concrete.cd`, `adapter/`, `concrete/` | `observer`, `command` | Adapts event bus observers that are also workflow commands and a command queue invoker. | `CombinedPatternEvaluationTest` | + +## Notes + +- Cases 6 through 13 are covered by pattern-focused JUnit tests in the main + `de.monticore.codeAdaption` test package. +- Cases 14 through 16 are covered by executable wrappers in + `CombinedPatternEvaluationTest`. diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/AdaptationWorkspace.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/AdaptationWorkspace.java new file mode 100644 index 00000000..8716a40e --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/AdaptationWorkspace.java @@ -0,0 +1,147 @@ +package de.monticore.codeAdaption; + +import de.monticore.codeAdaption.utils.JavaLoader; +import java.io.IOException; +import java.nio.file.AtomicMoveNotSupportedException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Objects; + +/** Owns normalized paths, temporary directories, and transactional output publication. */ +final class AdaptationWorkspace { + + private final Path referenceSource; + private final Path concreteSource; + private final Path output; + + AdaptationWorkspace(Path referenceSource, Path concreteSource, Path output) { + this.referenceSource = canonicalPath(referenceSource); + this.concreteSource = canonicalPath(concreteSource); + this.output = canonicalPath(output); + validatePaths(this.referenceSource, this.concreteSource, this.output); + } + + Path referenceSource() { + return referenceSource; + } + + Path concreteSource() { + return concreteSource; + } + + void validateReadOnlyInput(Path input, String label) { + rejectOverlap(label, canonicalPath(input), output); + } + + Path createStagingDirectory() { + try { + Files.createDirectories(output.getParent()); + return Files.createTempDirectory(output.getParent(), ".code-adaptation-staging-"); + } catch (IOException exception) { + throw new CodeAdaptationException("Could not create output staging directory", exception); + } + } + + Path createMappingDirectory(Path stagingDirectory) { + try { + Path directory = Files.createTempDirectory(stagingDirectory, ".mapping-"); + requireContained(stagingDirectory, directory); + return directory; + } catch (IOException exception) { + throw new CodeAdaptationException("Could not create mapping workspace", exception); + } + } + + void discard(Path directory) { + if (directory != null && Files.exists(directory)) { + JavaLoader.removeDirectory(directory); + } + } + + void publish(Path stagingDirectory) { + requireContained(output.getParent(), stagingDirectory); + Path backup = null; + try { + if (Files.exists(output)) { + backup = Files.createTempDirectory(output.getParent(), ".code-adaptation-backup-"); + Files.delete(backup); + moveDirectory(output, backup); + } + moveDirectory(stagingDirectory, output); + if (backup != null) { + JavaLoader.removeDirectory(backup); + } + } catch (IOException | RuntimeException exception) { + if (backup != null && Files.exists(backup)) { + try { + if (Files.exists(output)) { + moveDirectory(output, stagingDirectory); + } + if (!Files.exists(output)) { + moveDirectory(backup, output); + } + } catch (IOException restoreFailure) { + exception.addSuppressed(restoreFailure); + } + } + throw new CodeAdaptationException("Could not publish adapted code to " + output, exception); + } + } + + static void validatePaths(Path referenceSource, Path concreteSource, Path output) { + Path normalizedReference = normalizedPath(referenceSource); + Path normalizedConcrete = normalizedPath(concreteSource); + Path normalizedOutput = normalizedPath(output); + if (normalizedOutput.getParent() == null) { + throw new IllegalArgumentException( + "Output path must not be a filesystem root: " + normalizedOutput); + } + rejectOverlap("reference handwritten code", normalizedReference, normalizedOutput); + rejectOverlap("concrete handwritten code", normalizedConcrete, normalizedOutput); + } + + private static void rejectOverlap(String label, Path input, Path output) { + if (input.equals(output) || input.startsWith(output) || output.startsWith(input)) { + throw new IllegalArgumentException( + "Output path must not overlap " + label + ": " + output + " and " + input); + } + } + + private static Path normalizedPath(Path path) { + return Objects.requireNonNull(path, "path").toAbsolutePath().normalize(); + } + + private static Path canonicalPath(Path path) { + Path normalized = normalizedPath(path); + Path existing = normalized; + while (existing != null && !Files.exists(existing)) { + existing = existing.getParent(); + } + if (existing == null) { + return normalized; + } + try { + return existing.toRealPath().resolve(existing.relativize(normalized)).normalize(); + } catch (IOException exception) { + throw new CodeAdaptationException("Could not resolve path " + normalized, exception); + } + } + + private static void requireContained(Path parent, Path child) { + Path normalizedParent = normalizedPath(parent); + Path normalizedChild = normalizedPath(child); + if (!normalizedChild.startsWith(normalizedParent) || normalizedChild.equals(normalizedParent)) { + throw new IllegalArgumentException( + "Temporary path escapes its workspace: " + normalizedChild); + } + } + + private static void moveDirectory(Path source, Path target) throws IOException { + try { + Files.move(source, target, StandardCopyOption.ATOMIC_MOVE); + } catch (AtomicMoveNotSupportedException exception) { + Files.move(source, target); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/AdaptedCodeMerger.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/AdaptedCodeMerger.java new file mode 100644 index 00000000..36b75f53 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/AdaptedCodeMerger.java @@ -0,0 +1,615 @@ +package de.monticore.codeAdaption; + +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.codeAdaption.validator.CodeValidator; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTCompilationUnit; +import de.monticore.java.javadsl._ast.ASTImportDeclaration; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** Merges, filters, splits, and deduplicates Java AST units produced by mapping runs. */ +final class AdaptedCodeMerger { + + /** + * Caches platform-class lookups used while repairing imports. A cached {@code true} means the + * fully qualified name resolves, without class initialization, to a public top-level JDK type; + * such a type is already available through {@code java.lang} or a matching wildcard import. + */ + private static final Map PLATFORM_PUBLIC_TOP_LEVEL_TYPE_CACHE = + new ConcurrentHashMap<>(); + + /** + * Merges newly adapted units into output accumulated from earlier mapping passes. + * + *

Units are matched by package-qualified top-level identity, not by source-file path. Thus two + * passes producing {@code shipping.Port} contribute members to one unit, while {@code api.Port} + * remains separate. + */ + Set mergeAdaptedCode( + Set actualCode, + Set newAdaptedCode) { + Map merged = indexAndMerge(actualCode); + for (ASTOrdinaryCompilationUnit newAdapted : ordered(newAdaptedCode)) { + String key = compilationUnitKey(newAdapted); + merged.compute( + key, (k, existing) -> existing == null ? newAdapted : AdapterUtils.mergeAsts(existing, newAdapted)); + } + return new LinkedHashSet<>(merged.values()); + } + + /** + * Retains compilation units relevant to one mapping-specific incarnation context. + * + *

A unit is retained when a top-level Java type matches a reference-CD type having at least + * one incarnation in {@code context}. A unit explicitly marked {@code @Adapt(ignore = true)} is + * also retained: ignore prevents transformation of that type, but does not mean that its source + * file should disappear from the mapping output. + */ + Set filterCodeForMapping( + Set javaFiles, + CodeValidator validator, + IncarnationContext context, + CDModelIndex referenceIndex) { + validator.initializeTypeMatcher(javaFiles); + Set result = new LinkedHashSet<>(); + for (ASTOrdinaryCompilationUnit unit : javaFiles) { + JavaAstElemCollector collector = collect(unit); + + boolean mappedTopLevel = + collector.getAllTypeDeclarations().stream() + .map(validator::getMatchedType) + .filter(Optional::isPresent) + .map(Optional::get) + .flatMap(matching -> matching.getReferences().stream()) + .anyMatch( + reference -> StableElementKey.fromSymbol(reference, referenceIndex) + .map(context::getIncarnations) + .filter(incarnations -> !incarnations.isEmpty()) + .isPresent()); + boolean ignoredTopLevel = + collector.getAllTypeDeclarations().stream() + .map(validator::getMatchedType) + .filter(Optional::isPresent) + .map(Optional::get) + .anyMatch( + matching -> + !matching.mustBePerform() && matching.isExplicitAnnotation()); + if (mappedTopLevel || ignoredTopLevel) { + result.add(unit); + } + } + return result; + } + + /** + * Builds the final generated code on top of concrete handwritten classes. Adapted and concrete + * units with the same package-qualified top-level identity are merged. + * + *

For example, an adapted {@code adapter.Port} containing {@code void send()} can be relocated + * to a uniquely matching handwritten {@code concrete.Port}; the result remains in package {@code + * concrete} and contains {@code send()}. + */ + Set mergeAdaptedCodeIntoConcreteBase( + Set concreteCode, + Set adaptedCode, + CDModelIndex concreteIndex) { + + Map result = indexAndMerge(concreteCode); + Map mergedAdapted = indexAndMerge(adaptedCode); + Map relocations = findRelocations(result, mergedAdapted, concreteIndex); + Map> importsByOriginalPackage = + adaptedTypeImports(mergedAdapted, relocations); + Map> repairableMemberTypesByUnit = new LinkedHashMap<>(); + + // Every unit in adaptedCode has already passed filterCodeForMapping. Retaining that explicit + // selection avoids guessing from coincidental type-name prefixes or suffixes. + for (ASTOrdinaryCompilationUnit originalAdapted : mergedAdapted.values()) { + String originalKey = compilationUnitKey(originalAdapted); + ASTOrdinaryCompilationUnit adaptedUnit = originalAdapted.deepClone(); + Relocation relocation = relocations.get(originalKey); + addRelocationImports( + adaptedUnit, + importsByOriginalPackage.getOrDefault(packageName(originalAdapted), Map.of()), + relocation == null ? packageName(adaptedUnit) : relocation.targetPackage()); + + String key = compilationUnitKey(adaptedUnit); + ASTOrdinaryCompilationUnit concreteMatch = result.get(key); + ASTOrdinaryCompilationUnit mergeableAdapted = adaptedUnit; + if (concreteMatch == null && relocation != null) { + key = relocation.targetKey(); + concreteMatch = result.get(key); + if (concreteMatch.isPresentPackageDeclaration()) { + mergeableAdapted.setPackageDeclaration( + concreteMatch.getPackageDeclaration().deepClone()); + } else { + mergeableAdapted.setPackageDeclarationAbsent(); + } + } + Set repairableMemberTypes = unqualifiedMemberTypeNames(mergeableAdapted); + if (concreteMatch != null) { + // Imports affect every occurrence of a simple name in the compilation unit. If concrete + // handwritten code already used that name, changing its binding would be unsafe even when + // an adapted member also uses it. + repairableMemberTypes.removeAll(unqualifiedMemberTypeNames(concreteMatch)); + } + repairableMemberTypesByUnit + .computeIfAbsent(key, ignored -> new LinkedHashSet<>()) + .addAll(repairableMemberTypes); + result.put( + key, + concreteMatch == null + ? mergeableAdapted + : AdapterUtils.mergeAstsPreferringLeft(concreteMatch, mergeableAdapted)); + } + + repairMemberTypeImports(result, repairableMemberTypesByUnit); + + return new LinkedHashSet<>(result.values()); + } + + /** + * Imports final concrete declaration locations used by generated fields, methods and + * supertypes. Completion can introduce member types after the initial reference-CD import + * projection, and relocation can place those types in packages different from their adapted + * owner. + */ + private void repairMemberTypeImports( + Map units, + Map> repairableMemberTypesByUnit) { + Map> declarationsBySimpleName = new LinkedHashMap<>(); + for (ASTOrdinaryCompilationUnit unit : units.values()) { + String declarationPackage = packageName(unit); + for (ASTTypeDeclaration type : unit.getTypeDeclarationList()) { + declarationsBySimpleName + .computeIfAbsent(type.getName(), ignored -> new LinkedHashSet<>()) + .add(qualify(declarationPackage, type.getName())); + } + } + + for (Map.Entry unitEntry : units.entrySet()) { + ASTOrdinaryCompilationUnit unit = unitEntry.getValue(); + Set repairableMemberTypes = + repairableMemberTypesByUnit.getOrDefault(unitEntry.getKey(), Set.of()); + if (repairableMemberTypes.isEmpty()) { + continue; + } + Set referencedTypes = memberTypeNames(unit); + Set declaredSimpleNames = + unit.getTypeDeclarationList().stream() + .map(ASTTypeDeclaration::getName) + .collect(java.util.stream.Collectors.toSet()); + Set existingImports = + unit.getImportDeclarationList().stream() + .filter( + importDeclaration -> + !importDeclaration.isStatic() && !importDeclaration.isSTAR()) + .map(importDeclaration -> importDeclaration.getMCQualifiedName().getQName()) + .filter(qualifiedName -> qualifiedName.contains(".")) + .collect(java.util.stream.Collectors.toSet()); + Map explicitImportsBySimpleName = new LinkedHashMap<>(); + for (String existingImport : existingImports) { + explicitImportsBySimpleName.put(simpleName(existingImport), existingImport); + } + Set wildcardImportPackages = + unit.getImportDeclarationList().stream() + .filter( + importDeclaration -> + !importDeclaration.isStatic() && importDeclaration.isSTAR()) + .map(importDeclaration -> importDeclaration.getMCQualifiedName().getQName()) + .collect(java.util.stream.Collectors.toSet()); + Map requiredImports = new LinkedHashMap<>(); + for (JavaSourceNames.TypeReferenceName reference : referencedTypes) { + if (reference.qualified()) { + continue; + } + String simpleName = reference.simpleName(); + if (!repairableMemberTypes.contains(simpleName)) { + continue; + } + Set candidates = declarationsBySimpleName.getOrDefault(simpleName, Set.of()); + if (declaredSimpleNames.contains(simpleName) || candidates.isEmpty()) { + continue; + } + String explicitImport = explicitImportsBySimpleName.get(simpleName); + if (explicitImport != null) { + // A single-type import is an established binding. It may belong to handwritten code + // that shares a compilation unit with generated members, so never reinterpret it from + // coincidental declarations in the final output. + continue; + } + boolean samePackageCandidate = + candidates.stream() + .anyMatch(candidate -> packageName(candidate).equals(packageName(unit))); + if (samePackageCandidate) { + continue; + } + if (isImplicitJavaLangType(simpleName)) { + // The implicit java.lang binding has the same precedence as a pre-existing explicit + // import for this purpose. Generated code must use a qualified name if it means another + // type with the same simple name. + continue; + } + List matchingWildcardPackages = + wildcardImportPackages.stream() + .filter( + importedPackage -> + isAvailableThroughWildcardImport( + importedPackage, simpleName, candidates)) + .toList(); + if (matchingWildcardPackages.size() == 1) { + // Unrelated declarations do not make the wildcard binding ambiguous: only declarations + // from imported packages participate in that binding. + continue; + } + if (matchingWildcardPackages.size() > 1) { + throw new CodeAdaptationException( + "Cannot repair generated member type '" + + simpleName + + "' because multiple wildcard imports provide final declarations: " + + matchingWildcardPackages); + } + if (candidates.size() == 1) { + // A single-type import takes precedence over unrelated on-demand imports. + requiredImports.put(simpleName, candidates.iterator().next()); + } else if (candidates.size() > 1) { + throw new CodeAdaptationException( + "Cannot import generated member type '" + + simpleName + + "' because final output contains multiple declarations: " + + candidates); + } + } + addRelocationImports(unit, requiredImports, packageName(unit)); + } + } + + /** Returns whether the running Java platform implicitly provides the simple name. */ + private boolean isImplicitJavaLangType(String simpleName) { + if (simpleName == null || simpleName.isBlank() || simpleName.contains(".")) { + return false; + } + return isLoadablePublicTopLevelType("java.lang." + simpleName); + } + + /** + * A wildcard import covers either a type produced in the final output or a public top-level JDK + * type. Checking both avoids adding redundant explicit imports after relocation. + */ + private boolean isAvailableThroughWildcardImport( + String importedPackage, String simpleName, Set outputCandidates) { + String qualifiedName = qualify(importedPackage, simpleName); + return outputCandidates.contains(qualifiedName) + || isLoadablePublicTopLevelType(qualifiedName); + } + + private boolean isLoadablePublicTopLevelType(String qualifiedName) { + return PLATFORM_PUBLIC_TOP_LEVEL_TYPE_CACHE.computeIfAbsent( + qualifiedName, AdaptedCodeMerger::loadPublicTopLevelType); + } + + /** + * Probes only the JDK platform class loader and does not initialize the class. Nested and + * non-public classes are deliberately rejected because a Java wildcard import cannot expose + * them as top-level source types. + */ + private static boolean loadPublicTopLevelType(String qualifiedName) { + try { + Class type = + Class.forName(qualifiedName, false, ClassLoader.getPlatformClassLoader()); + return type.getEnclosingClass() == null + && java.lang.reflect.Modifier.isPublic(type.getModifiers()); + } catch (ClassNotFoundException | LinkageError ignored) { + return false; + } + } + + /** Collects unqualified signature names that originated in an adapted compilation unit. */ + private Set unqualifiedMemberTypeNames(ASTOrdinaryCompilationUnit unit) { + return memberTypeNames(unit).stream() + .filter(reference -> !reference.qualified()) + .map(JavaSourceNames.TypeReferenceName::simpleName) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + } + + /** Collects type names appearing in declaration signatures that may require final imports. */ + private Set memberTypeNames( + ASTOrdinaryCompilationUnit unit) { + Set names = new LinkedHashSet<>(); + JavaAstElemCollector collector = collect(unit); + for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { + collector.getAllFSuperTypeDeclarations(type).forEach(value -> collectTypeNames(value, names)); + collector + .getAllFieldDeclarations(type) + .forEach(field -> collectTypeNames(field.getMCType(), names)); + collector + .getAllMethodDeclarations(type) + .forEach( + method -> { + collectTypeNames(method.getMCReturnType(), names); + collector + .getAllParameters(type, method) + .forEach(parameter -> collectTypeNames(parameter.getMCType(), names)); + }); + } + return names; + } + + /** Retains qualified identity while traversing arrays, generics, and wildcard bounds. */ + private void collectTypeNames( + de.monticore.ast.ASTNode type, Set names) { + names.addAll(JavaSourceNames.typeReferences(JavaLoader.print(type))); + } + + /** + * Finds adapted units that must move to an existing concrete handwritten package before merge. + * + *

The result maps the adapted unit's original package-qualified identity to its concrete + * target identity and package. Relocation requires one unique concrete Java declaration with the + * same concrete-CD type name; zero matches leave the unit in place and multiple matches fail. + */ + private Map findRelocations( + Map concreteCode, + Map adaptedCode, + CDModelIndex concreteIndex) { + Map relocations = new LinkedHashMap<>(); + for (Map.Entry entry : adaptedCode.entrySet()) { + if (concreteCode.containsKey(entry.getKey())) { + continue; + } + Optional> target = + uniqueConcreteTypeMatch(concreteCode, entry.getValue(), concreteIndex); + if (target.isEmpty()) { + continue; + } + ASTOrdinaryCompilationUnit adaptedUnit = entry.getValue(); + ASTOrdinaryCompilationUnit concreteUnit = target.get().getValue(); + String simpleName = adaptedUnit.getTypeDeclarationList().get(0).getName(); + relocations.put( + entry.getKey(), + new Relocation( + simpleName, + target.get().getKey(), + packageName(concreteUnit))); + } + return relocations; + } + + /** + * Indexes final adapted type locations for cross-package import repair. + * + *

The outer key is the type's original package. Each inner map is {@code simple type name -> + * final qualified name}. For example, relocating {@code adapter.Port} to {@code concrete.Port} + * records {@code adapter -> {Port=concrete.Port}}, allowing other units originally in {@code + * adapter} to import the relocated type. + */ + private Map> adaptedTypeImports( + Map adaptedCode, + Map relocations) { + Map> result = new LinkedHashMap<>(); + for (Map.Entry entry : adaptedCode.entrySet()) { + ASTOrdinaryCompilationUnit unit = entry.getValue(); + if (unit.getTypeDeclarationList().size() != 1) { + continue; + } + String originalPackage = packageName(unit); + String typeName = unit.getTypeDeclarationList().get(0).getName(); + Relocation relocation = relocations.get(entry.getKey()); + String qualifiedTarget = + relocation == null + ? qualify(originalPackage, typeName) + : qualify(relocation.targetPackage(), typeName); + Map bySimpleName = + result.computeIfAbsent(originalPackage, ignored -> new LinkedHashMap<>()); + String conflict = bySimpleName.putIfAbsent(typeName, qualifiedTarget); + if (conflict != null && !conflict.equals(qualifiedTarget)) { + throw new CodeAdaptationException( + "Ambiguous concrete package for adapted type '" + + typeName + + "': " + + conflict + + " and " + + qualifiedTarget); + } + } + return result; + } + + private void addRelocationImports( + ASTOrdinaryCompilationUnit unit, + Map relocatedTypes, + String finalPackage) { + Set declaredTypes = + unit.getTypeDeclarationList().stream() + .map(ASTTypeDeclaration::getName) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + Map importsBySimpleName = new LinkedHashMap<>(); + for (ASTImportDeclaration existingImport : + new ArrayList<>(unit.getImportDeclarationList())) { + String qualifiedName = existingImport.getMCQualifiedName().getQName(); + String importedSimpleName = simpleName(qualifiedName); + if (!qualifiedName.contains(".") && relocatedTypes.containsKey(importedSimpleName)) { + unit.removeImportDeclaration(existingImport); + } else { + importsBySimpleName.put(importedSimpleName, qualifiedName); + } + } + for (Map.Entry relocatedType : relocatedTypes.entrySet()) { + String simpleName = relocatedType.getKey(); + String qualifiedName = relocatedType.getValue(); + if (declaredTypes.contains(simpleName) || packageName(qualifiedName).equals(finalPackage)) { + continue; + } + String conflict = importsBySimpleName.putIfAbsent(simpleName, qualifiedName); + if (conflict != null && !conflict.equals(qualifiedName)) { + throw new CodeAdaptationException( + "Cannot import relocated type '" + + qualifiedName + + "' because '" + + conflict + + "' already uses the simple name '" + + simpleName + + "'"); + } + if (conflict == null) { + unit.addImportDeclaration(parseImport(qualifiedName)); + } + } + } + + private ASTImportDeclaration parseImport(String qualifiedName) { + try { + Optional parsed = + JavaDSLMill.parser() + .parse_StringCompilationUnit( + "import " + qualifiedName + ";" + System.lineSeparator() + "class Holder {}"); + if (parsed.isEmpty() || !(parsed.get() instanceof ASTOrdinaryCompilationUnit unit)) { + throw new CodeAdaptationException("Could not create Java import for " + qualifiedName); + } + return unit.getImportDeclaration(0).deepClone(); + } catch (IOException exception) { + throw new CodeAdaptationException("Could not create Java import for " + qualifiedName, exception); + } + } + + private Optional> uniqueConcreteTypeMatch( + Map concreteCode, + ASTOrdinaryCompilationUnit adaptedUnit, + CDModelIndex concreteIndex) { + if (adaptedUnit.getTypeDeclarationList().size() != 1) { + return Optional.empty(); + } + String adaptedType = adaptedUnit.getTypeDeclarationList().get(0).getName(); + boolean isConcreteType = concreteIndex.hasType(adaptedType); + if (!isConcreteType) { + return Optional.empty(); + } + List> candidates = + concreteCode.entrySet().stream() + .filter( + entry -> + entry.getValue().getTypeDeclarationList().stream() + .anyMatch(type -> adaptedType.equals(type.getName()))) + .toList(); + if (candidates.size() > 1) { + throw new CodeAdaptationException( + "Cannot relocate adapted type '" + + adaptedType + + "' because concrete Java declares it in multiple packages: " + + candidates.stream().map(Map.Entry::getKey).sorted().toList()); + } + return candidates.size() == 1 ? Optional.of(candidates.get(0)) : Optional.empty(); + } + + Set splitCompilationUnitsByType( + Set units) { + Set result = new LinkedHashSet<>(); + for (ASTOrdinaryCompilationUnit unit : ordered(units)) { + List types = new ArrayList<>(unit.getTypeDeclarationList()); + if (types.size() <= 1) { + result.add(unit); + continue; + } + + for (ASTTypeDeclaration type : types) { + ASTOrdinaryCompilationUnit copy = unit.deepClone(); + for (ASTTypeDeclaration copiedType : new ArrayList<>(copy.getTypeDeclarationList())) { + if (!copiedType.getName().equals(type.getName())) { + copy.removeTypeDeclaration(copiedType); + } + } + + String fileName = type.getName() + ".java"; + copy.get_SourcePositionStart().setFileName(fileName); + result.add(copy); + } + } + return result; + } + + /** + * Indexes units by package-qualified top-level identity and merges duplicate identities. + * Source paths do not participate in the key. + */ + private Map indexAndMerge( + Set files) { + Map byQualifiedType = new LinkedHashMap<>(); + for (ASTOrdinaryCompilationUnit file : ordered(files)) { + String key = compilationUnitKey(file); + ASTOrdinaryCompilationUnit existing = byQualifiedType.get(key); + if (existing == null) { + byQualifiedType.put(key, file); + } else { + byQualifiedType.put(key, AdapterUtils.mergeAsts(existing, file)); + } + } + return byQualifiedType; + } + + private List ordered(Set files) { + return files.stream() + .sorted( + Comparator.comparing(this::compilationUnitKey) + .thenComparing(AdapterUtils::getFileName)) + .toList(); + } + + /** Returns the package-qualified identity of a split compilation unit. */ + private String compilationUnitKey(ASTOrdinaryCompilationUnit unit) { + String packageName = packageName(unit); + String typeIdentity = + unit.getTypeDeclarationList().stream() + .map(ASTTypeDeclaration::getName) + .sorted() + .reduce((left, right) -> left + "+" + right) + .orElseGet(() -> AdapterUtils.getSimpleFileName(unit)); + return packageName.isEmpty() ? typeIdentity : packageName + "." + typeIdentity; + } + + private String packageName(ASTOrdinaryCompilationUnit unit) { + return unit.isPresentPackageDeclaration() + ? unit.getPackageDeclaration().getMCQualifiedName().getQName() + : ""; + } + + private String packageName(String qualifiedName) { + int separator = qualifiedName.lastIndexOf('.'); + return separator < 0 ? "" : qualifiedName.substring(0, separator); + } + + private String simpleName(String qualifiedName) { + int separator = qualifiedName.lastIndexOf('.'); + return separator < 0 ? qualifiedName : qualifiedName.substring(separator + 1); + } + + private String qualify(String packageName, String simpleName) { + return packageName.isEmpty() ? simpleName : packageName + "." + simpleName; + } + + private JavaAstElemCollector collect(ASTOrdinaryCompilationUnit unit) { + JavaAstElemCollector collector = new JavaAstElemCollector(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(collector); + unit.accept(traverser); + return collector; + } + + private record Relocation(String simpleName, String targetKey, String targetPackage) {} +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdaptationException.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdaptationException.java new file mode 100644 index 00000000..ef13ae28 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdaptationException.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption; + +/** + * Runtime exception for adaptation setup problems that would lead to invalid generated Java. + */ +public class CodeAdaptationException extends RuntimeException { + public CodeAdaptationException(String message) { + super(message); + } + + public CodeAdaptationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapter.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapter.java index 21abdd5f..6da88a5d 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapter.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapter.java @@ -1,43 +1,69 @@ package de.monticore.codeAdaption; -import static de.monticore.codeAdaption.utils.AdapterUtils.getFileName; - import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.cdconformance.CDConfParameter; import de.monticore.cdconformance.CDConformanceChecker; -import de.monticore.codeAdaption.handler.BasicUpdateHandler; -import de.monticore.codeAdaption.updater.CodeUpdater; -import de.monticore.codeAdaption.updater.spoonUpdater.SpoonUpdater; +import de.monticore.codeAdaption.context.AdaptationContextFactory; +import de.monticore.codeAdaption.context.AdaptationContextFactory.AdaptationContextResult; +import de.monticore.codeAdaption.context.ConcretizationService; +import de.monticore.codeAdaption.context.GroupingMappingService; +import de.monticore.codeAdaption.context.MappingConformanceService; +import de.monticore.codeAdaption.MappingAdaptationRunner.AdaptationPass; +import de.monticore.codeAdaption.handler.multiIncarnation.AdaptationConflictDetector; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.MatcherHelper; import de.monticore.codeAdaption.utils.AdapterParam; -import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.codeAdaption.utils.CDImportProjector; +import de.monticore.codeAdaption.utils.CDModelIndex; import de.monticore.codeAdaption.utils.JavaLoader; -import de.monticore.codeAdaption.utils.visitors.AnnotationRemover; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; import de.monticore.codeAdaption.validator.CodeValidator; import de.monticore.java.javadsl.JavaDSLMill; import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; import de.monticore.java.javadsl._visitor.JavaDSLTraverser; -import de.se_rwth.commons.logging.Log; +import de.monticore.symboltable.ISymbol; import java.io.File; +import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +/** + * Adapts handwritten reference Java to a concrete class diagram through + * mapping-specific transformation passes. + * + *

A failed run never publishes its staging directory over existing output. + */ public class CodeAdapter { - protected Set adapterParams; - protected Set confParams; + /** Maximum number of Cartesian multi-incarnation selections accepted for one source unit. */ + private static final int MAX_TYPE_SELECTIONS = 1024; + + private final Set adapterParams; + private final Set confParams; + /** + * Creates an adapter with explicit Java matching and CD-conformance policies. + * + * @param adapterParams enabled Java matching strategies and unmatched-element policies + * @param confParams enabled CD conformance parameters + */ public CodeAdapter(Set adapterParams, Set confParams) { - this.confParams = confParams; - this.adapterParams = adapterParams; + this.adapterParams = Set.copyOf(Objects.requireNonNull(adapterParams, "adapterParams")); + this.confParams = Set.copyOf(Objects.requireNonNull(confParams, "confParams")); } - /*** + /** + * Adapts reference Java code to a concrete class diagram without completing the concrete model + * first. * - * @param referenceCD the reference class diagram. - * @param concreteCD, the concrete class diagram. - * @param refHwcPath the handwritten reference-code. - * @param conHwcPath path to the concrete code, - * @param mappings different maping names. - * @param outputPath the output path + * @param referenceCD reference class diagram + * @param concreteCD concrete class diagram + * @param mappings mapping stereotype names to apply + * @param refHwcPath reference handwritten-code directory + * @param conHwcPath concrete handwritten-code directory + * @param outputPath output directory + * @throws CodeAdaptationException if validation or deterministic adaptation fails */ public void adapt( File referenceCD, @@ -46,84 +72,536 @@ public void adapt( Path refHwcPath, Path conHwcPath, Path outputPath) { + adapt(referenceCD, concreteCD, mappings, refHwcPath, conHwcPath, outputPath, false, true); + } + + /** + * Adapts reference Java code to a concrete class diagram. + * + *

With {@code useConcretization=true}, cdconcretization may complete the concrete CD before + * adaptation. With {@code useConcretization=false}, incarnation contexts are derived manually from + * stereotypes and deterministic name rules, conflicts are reported before the output directory is + * cleaned, and the concrete CD is not changed. + * + *

{@code useCommonParentForMultipleIncarnations} permits manual adaptation to represent an + * exact group of concrete incarnations through a common concrete interface. For example, if + * {@code Payment} maps to {@code CreditCard} and {@code Invoice}, and those are exactly the + * concrete implementers of {@code PaymentMethod}, shared Java declarations may use {@code + * PaymentMethod}. A broader interface that also has unrelated implementers is not selected. + * + * @param referenceCD reference class diagram + * @param concreteCD concrete class diagram + * @param mappings mapping stereotype names to apply + * @param refHwcPath reference handwritten-code directory + * @param conHwcPath concrete handwritten-code directory + * @param outputPath output directory published only after a successful run + * @param useConcretization whether to complete the concrete CD before adaptation + * @param useCommonParentForMultipleIncarnations whether a common concrete interface whose + * implementers exactly match an incarnation group may replace the individual incarnation + * types in shared Java declarations + * @throws CodeAdaptationException if validation, conflict detection, or adaptation fails + */ + public void adapt( + File referenceCD, + File concreteCD, + Set mappings, + Path refHwcPath, + Path conHwcPath, + Path outputPath, + boolean useConcretization, + boolean useCommonParentForMultipleIncarnations) { + adaptInternal( + referenceCD, + concreteCD, + mappings, + refHwcPath, + conHwcPath, + outputPath, + useConcretization, + useCommonParentForMultipleIncarnations); + } + + private void adaptInternal( + File referenceCD, + File concreteCD, + Set mappings, + Path refHwcPath, + Path conHwcPath, + Path outputPath, + boolean useConcretization, + boolean useCommonParentForMultipleIncarnations) { + AdaptationWorkspace workspace = + new AdaptationWorkspace(refHwcPath, conHwcPath, outputPath); + workspace.validateReadOnlyInput(referenceCD.toPath(), "reference class diagram"); + workspace.validateReadOnlyInput(concreteCD.toPath(), "concrete class diagram"); + Path normalizedRefHwcPath = workspace.referenceSource(); + Path normalizedConHwcPath = workspace.concreteSource(); + SortedSet validatedMappingsInOrder = validatedMappings(mappings); // load CD models - ASTCDCompilationUnit refCD = JavaLoader.loadCD(referenceCD); - ASTCDCompilationUnit conCD = JavaLoader.loadCD(concreteCD); + ASTCDCompilationUnit refCD = JavaLoader.parseCD(referenceCD.getPath()); + ASTCDCompilationUnit conCD = JavaLoader.parseCD(concreteCD.getPath()); + CDModelIndex inputConcreteIndex = CDModelIndex.of(conCD); + CDModelIndex referenceIndex = CDModelIndex.of(refCD); + MappingConformanceService conformanceService = new MappingConformanceService(confParams); - Set adaptedCode = new LinkedHashSet<>(); + if (useConcretization) { + conCD = + new ConcretizationService(confParams) + .completeConcreteCD(conCD, refCD, validatedMappingsInOrder); + } + CDModelIndex conIndex = CDModelIndex.of(conCD); + AdaptedCodeMerger codeMerger = new AdaptedCodeMerger(); + OutputCodeService outputCode = new OutputCodeService(); - for (String mapping : mappings) { + // Build each context and checker once, then reuse that exact checker state in handlers. + Map contextResults = + new AdaptationContextFactory(confParams, conformanceService) + .buildResults(referenceIndex, conIndex, validatedMappingsInOrder, useConcretization); + Map incarnationContextsByMapping = new LinkedHashMap<>(); + Map checkers = new LinkedHashMap<>(); + Map validators = new LinkedHashMap<>(); + for (String mapping : validatedMappingsInOrder) { + AdaptationContextResult result = contextResults.get(mapping); + incarnationContextsByMapping.put(mapping, result.context()); + checkers.put(mapping, result.checker()); + validators.put(mapping, new CodeValidator(refCD, adapterParams)); + } + + SortedSet fallbackMappings = + contextResults.entrySet().stream() + .filter(entry -> !entry.getValue().conformanceValid()) + .map(Map.Entry::getKey) + .collect( + java.util.stream.Collectors.toCollection(TreeSet::new)); + if (!useConcretization || !fallbackMappings.isEmpty()) { + Set mappingsToValidate = + useConcretization ? fallbackMappings : validatedMappingsInOrder; + Map contextsToValidate = new LinkedHashMap<>(); + mappingsToValidate.forEach( + mapping -> contextsToValidate.put(mapping, incarnationContextsByMapping.get(mapping))); + AdaptationConflictDetector.validate( + referenceIndex, + conIndex, + mappingsToValidate, + contextsToValidate, + confParams, + useCommonParentForMultipleIncarnations); + } - // check conformance - CDConformanceChecker checker = new CDConformanceChecker(confParams); - if (!checker.checkConformance(conCD, refCD, mapping)) { - Log.error("The concrete CD is not Conform to the Reference CD"); + // Validate before creating staging directories or changing existing output. + for (String mapping : validatedMappingsInOrder) { + CodeValidator validator = validators.get(mapping); + if (validator == null || !validator.isValid(refCD, normalizedRefHwcPath)) { + throw new CodeAdaptationException( + "Reference code is not valid for the reference CD (mapping '" + mapping + "')"); } + } + + Set refCode = JavaLoader.readJavaCode(normalizedRefHwcPath); + CDImportProjector.project(refCode, refCD, conCD); + Path stagingPath = workspace.createStagingDirectory(); + boolean published = false; + try { + Set adaptedCode = new LinkedHashSet<>(); + MappingAdaptationRunner passRunner = + new MappingAdaptationRunner( + workspace, + codeMerger, + stagingPath, + referenceIndex, + conIndex, + inputConcreteIndex, + useCommonParentForMultipleIncarnations); - // check validity of the reference code - CodeValidator validator = new CodeValidator(refCD, adapterParams); - if (!validator.isValid(refCD, refHwcPath)) { - Log.error("The reference code is not valid for the reference CD"); + for (String mapping : validatedMappingsInOrder) { + if (!incarnationContextsByMapping.containsKey(mapping)) { + continue; // Skip mappings that failed to build contexts } - // build updater and clean output directory - CodeUpdater updater = new SpoonUpdater(); - updater.setCodePath(refHwcPath); - updater.setOutputDirectory(outputPath); - JavaLoader.removeDirectory(outputPath); + IncarnationContext ctx = incarnationContextsByMapping.get(mapping); + Map groupingMappings = + useCommonParentForMultipleIncarnations + ? new GroupingMappingService().compute(ctx) + : Collections.emptyMap(); + Set mappingCode = cloneUnits(refCode); + mappingCode = codeMerger.splitCompilationUnitsByType(mappingCode); + mappingCode = + codeMerger.filterCodeForMapping( + mappingCode, validators.get(mapping), ctx, referenceIndex); - // update handler - BasicUpdateHandler handler = - new BasicUpdateHandler(refCD, conCD, conHwcPath, checker, updater, validator); + Set mappingAdaptedCode = + passRunner.run( + mapping, + mappingCode, + buildAdaptationPasses( + mappingCode, + validators.get(mapping), + ctx, + referenceIndex, + conIndex, + inputConcreteIndex, + useCommonParentForMultipleIncarnations), + checkers.get(mapping), + validators.get(mapping), + ctx, + groupingMappings); + adaptedCode = codeMerger.mergeAdaptedCode(adaptedCode, mappingAdaptedCode); + } - // perform updates - handler.handleUpdate(JavaLoader.readJavaCode(refHwcPath)); + // Final output to destination + if (!adaptedCode.isEmpty()) { + Set concreteCode = + Files.exists(normalizedConHwcPath) + ? JavaLoader.readJavaCode(normalizedConHwcPath) + : new LinkedHashSet<>(); + Set finalCode = + codeMerger.mergeAdaptedCodeIntoConcreteBase(concreteCode, adaptedCode, conIndex); - // clean code - cleanCode(outputPath); - adaptedCode = mergeAdaptedCode(adaptedCode, JavaLoader.readJavaCode(outputPath)); + JavaLoader.printAST(finalCode, stagingPath); + // Clean up @Adapt annotations and invalid imports in both adaptation modes. + outputCode.cleanCode(stagingPath); + } + outputCode.copyConcreteFiles(normalizedConHwcPath, stagingPath); + workspace.publish(stagingPath); + published = true; + } finally { + if (!published) { + workspace.discard(stagingPath); + } } - JavaLoader.printAST(adaptedCode, outputPath); } - private Set mergeAdaptedCode( - Set actualCode, Set newAdaptedCode) { - if (actualCode.isEmpty()) { - return newAdaptedCode; - } + static void validatePaths(Path refHwcPath, Path conHwcPath, Path outputPath) { + AdaptationWorkspace.validatePaths(refHwcPath, conHwcPath, outputPath); + } - for (ASTOrdinaryCompilationUnit newAdapted : newAdaptedCode) { - Optional actual = - actualCode.stream().filter(f -> getFileName(f).equals(getFileName(newAdapted))).findAny(); - if (actual.isEmpty()) { + private static Set cloneUnits( + Set units) { + Set clones = new LinkedHashSet<>(); + units.forEach(unit -> clones.add(unit.deepClone())); + return clones; + } - actualCode.add(newAdapted); + private static List buildAdaptationPasses( + Set units, + CodeValidator validator, + IncarnationContext context, + CDModelIndex referenceIndex, + CDModelIndex concreteIndex, + CDModelIndex inputConcreteIndex, + boolean useCommonParentForMultipleIncarnations) { + List passes = new ArrayList<>(); + boolean hasDefaultPass = false; + Set defaultOutputTypeNames = new LinkedHashSet<>(); + for (ASTOrdinaryCompilationUnit unit : units) { + Set relevantTypes = new LinkedHashSet<>(); + JavaAstElemCollector collector = collectJavaElements(unit); + for (var type : collector.getAllTypeDeclarations()) { + addRelevantTypeReferences( + validator.getMatchedType(type), + context, + relevantTypes, + referenceIndex, + useCommonParentForMultipleIncarnations); + for (var field : collector.getAllFieldDeclarations(type)) { + addRelevantTypeReferences( + validator.getMatchedField(type, field), + context, + relevantTypes, + referenceIndex, + useCommonParentForMultipleIncarnations); + } + for (var supertype : collector.getAllFSuperTypeDeclarations(type)) { + addRelevantTypeReferences( + validator.getMatchedSupertype(type, supertype), + context, + relevantTypes, + referenceIndex, + useCommonParentForMultipleIncarnations); + } + for (var method : collector.getAllMethodDeclarations(type)) { + addRelevantTypeReferences( + validator.getMatchedMethod(type, method), + context, + relevantTypes, + referenceIndex, + useCommonParentForMultipleIncarnations); + for (var parameter : collector.getAllParameters(type, method)) { + addRelevantTypeReferences( + validator.getMatchedParameter(type, method, parameter), + context, + relevantTypes, + referenceIndex, + useCommonParentForMultipleIncarnations); + } + for (var local : collector.getAllLocVariables(type, method)) { + addRelevantTypeReferences( + validator.getMatchedLocalVariable(type, method, local), + context, + relevantTypes, + referenceIndex, + useCommonParentForMultipleIncarnations); + } + } + } + List orderedReferences = + relevantTypes.stream() + .sorted(Comparator.comparing(StableElementKey::signature)) + .toList(); + if (orderedReferences.isEmpty()) { + hasDefaultPass = true; + defaultOutputTypeNames.addAll( + expectedOutputTypeNames(unit, validator, context, Map.of(), referenceIndex)); } else { - actualCode.add(AdapterUtils.mergeAsts(actual.get(), newAdapted)); + for (Map selection : + buildCompleteTypeSelections( + orderedReferences, + context, + referenceIndex, + concreteIndex, + inputConcreteIndex)) { + passes.add( + new AdaptationPass( + selection, + expectedOutputTypeNames(unit, validator, context, selection, referenceIndex))); + } } } - return actualCode; + if (hasDefaultPass) { + passes.add(0, new AdaptationPass(Map.of(), Set.copyOf(defaultOutputTypeNames))); + } + return passes; } - /*** - * clean the annotations and further extra information - * in the adapted code. - * @param codePath the code path. + /** + * Builds the owner-aware Java element index used while planning multi-incarnation passes for one + * compilation unit. */ - private static void cleanCode(Path codePath) { + private static JavaAstElemCollector collectJavaElements(ASTOrdinaryCompilationUnit unit) { + JavaAstElemCollector collector = new JavaAstElemCollector(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(collector); + unit.accept(traverser); + return collector; + } - Set asts = JavaLoader.readJavaCode(codePath); + /** + * Adds reference types that require pass expansion because a performing match has multiple + * concrete incarnations. Exact common-grouping sets stay in a single grouped pass, and non-type + * references do not participate in type selection. + */ + private static void addRelevantTypeReferences( + Optional matching, + IncarnationContext context, + Set relevantTypes, + CDModelIndex referenceIndex, + boolean useCommonParentForMultipleIncarnations) { + if (matching.isEmpty() || !matching.get().mustBePerform()) { + return; + } + for (ISymbol reference : matching.get().getReferences()) { + if (!(reference instanceof de.monticore.cdbasis._symboltable.CDTypeSymbol)) { + continue; + } + List incarnations = + StableElementKey.fromSymbol(reference, referenceIndex) + .map(context::getIncarnations) + .orElseGet(List::of); + if (incarnations.size() < 2 + || (useCommonParentForMultipleIncarnations + && isExactGroupingSet(context, incarnations))) { + continue; + } + StableElementKey.fromSymbol(reference, referenceIndex) + .ifPresent(relevantTypes::add); + } + } - JavaDSLTraverser traverser = JavaDSLMill.traverser(); - AnnotationRemover remover = new AnnotationRemover(); - traverser.add4JavaDSL(remover); - traverser.add4JavaLight(remover); - traverser.add4MCCommonStatements(remover); - traverser.add4MCVarDeclarationStatements(remover); + private static boolean isExactGroupingSet( + IncarnationContext context, List incarnations) { + Set incarnationNames = + incarnations.stream() + .map(element -> element.key().getName()) + .collect(java.util.stream.Collectors.toSet()); + Set derivedGroupings = + incarnationNames.stream() + .map(name -> groupingName(context, name)) + .flatMap(Optional::stream) + .collect(java.util.stream.Collectors.toSet()); + if (derivedGroupings.size() == 1) { + String grouping = derivedGroupings.iterator().next(); + boolean everyIncarnationBelongsToGrouping = + incarnationNames.stream() + .allMatch( + incarnation -> + grouping.equals(incarnation) + || groupingName(context, incarnation) + .filter(grouping::equals) + .isPresent()); + if (everyIncarnationBelongsToGrouping) { + return true; + } + } + for (String possibleGrouping : incarnationNames) { + boolean foundImplementer = false; + boolean exact = true; + for (String incarnation : incarnationNames) { + if (possibleGrouping.equals(incarnation)) { + continue; + } + Optional grouping = groupingName(context, incarnation); + foundImplementer |= grouping.isPresent(); + if (grouping.isEmpty() || !possibleGrouping.equals(grouping.get())) { + exact = false; + break; + } + } + if (exact && foundImplementer) { + return true; + } + } + return false; + } + + private static Set expectedOutputTypeNames( + ASTOrdinaryCompilationUnit unit, + CodeValidator validator, + IncarnationContext context, + Map selection, + CDModelIndex referenceIndex) { + Set result = new LinkedHashSet<>(); + for (var type : unit.getTypeDeclarationList()) { + Optional matching = validator.getMatchedType(type); + if (matching.isEmpty() || !matching.get().mustBePerform()) { + result.add(type.getName()); + continue; + } + boolean resolved = false; + List concreteReferences = new ArrayList<>(); + for (ISymbol reference : matching.get().getReferences()) { + IncarnationContext.MappedElement selected = + selectedIncarnation(reference, selection, context, referenceIndex); + concreteReferences.add(selected == null ? reference : selected.symbol()); + resolved |= selected != null; + } + String template = + matching.get().getGenerateTemplate() != null + && !matching.get().getGenerateTemplate().isEmpty() + ? matching.get().getGenerateTemplate() + : matching.get().getTemplate(); + if (resolved && template != null) { + result.add(MatcherHelper.fillTemplate(template, concreteReferences)); + } else { + result.add(type.getName()); + } + } + return Set.copyOf(result); + } + + private static IncarnationContext.MappedElement selectedIncarnation( + ISymbol reference, + Map selection, + IncarnationContext context, + CDModelIndex referenceIndex) { + Optional referenceKey = + StableElementKey.fromSymbol(reference, referenceIndex); + IncarnationContext.MappedElement selected = referenceKey.map(selection::get).orElse(null); + if (selected != null) { + return selected; + } + List incarnations = + referenceKey.map(context::getIncarnations).orElseGet(List::of); + return incarnations.size() == 1 ? incarnations.get(0) : null; + } + + private static SortedSet validatedMappings(Set mappings) { + if (mappings == null || mappings.isEmpty()) { + throw new IllegalArgumentException("At least one mapping is required"); + } + SortedSet ordered = new TreeSet<>(); + for (String mapping : mappings) { + if (mapping == null || mapping.isBlank()) { + throw new IllegalArgumentException("Mapping names must not be null or blank"); + } + ordered.add(mapping); + } + return Collections.unmodifiableSortedSet(ordered); + } - asts.forEach(ast -> ast.accept(traverser)); + private static List> + buildCompleteTypeSelections( + List referenceTypes, + IncarnationContext context, + CDModelIndex referenceIndex, + CDModelIndex concreteIndex, + CDModelIndex inputConcreteIndex) { + List> selections = new ArrayList<>(); + selections.add(new LinkedHashMap<>()); + for (StableElementKey referenceType : referenceTypes) { + List incarnations = + context.getIncarnations(referenceType).stream() + .collect(java.util.stream.Collectors.toCollection(ArrayList::new)); + incarnations.removeIf(incarnation -> !concreteIndex.hasType(incarnation.key().getName())); + String referenceName = referenceType.getName(); + if (incarnations.size() > 1 && !inputConcreteIndex.hasType(referenceName)) { + incarnations.removeIf(incarnation -> referenceName.equals(incarnation.key().getName())); + } + List sameKindIncarnations = + incarnations.stream() + .filter( + incarnation -> + sameTypeKind( + referenceIndex.type(referenceName).orElse(null), + concreteIndex.type(incarnation.key().getName()).orElse(null))) + .toList(); + if (!sameKindIncarnations.isEmpty()) { + incarnations = new ArrayList<>(sameKindIncarnations); + } + incarnations.sort(Comparator.comparing(incarnation -> incarnation.key().signature())); + if (incarnations.isEmpty()) { + throw new CodeAdaptationException( + "No incarnations available for reference type '" + referenceType.getName() + "'"); + } + long newSize = (long) selections.size() * incarnations.size(); + if (newSize > MAX_TYPE_SELECTIONS) { + throw new CodeAdaptationException( + "Multi-incarnation type selections exceed the safe limit of " + + MAX_TYPE_SELECTIONS + + " runs"); + } + List> expanded = + new ArrayList<>((int) newSize); + for (Map selection : selections) { + for (IncarnationContext.MappedElement incarnation : incarnations) { + Map copy = + new LinkedHashMap<>(selection); + copy.put(referenceType, incarnation); + expanded.add(Map.copyOf(copy)); + } + } + selections = expanded; + } + return selections; + } - JavaLoader.printAST(asts, codePath); + private static boolean sameTypeKind( + de.monticore.cdbasis._ast.ASTCDType reference, + de.monticore.cdbasis._ast.ASTCDType incarnation) { + return (reference instanceof de.monticore.cdbasis._ast.ASTCDClass + && incarnation instanceof de.monticore.cdbasis._ast.ASTCDClass) + || (reference instanceof de.monticore.cdinterfaceandenum._ast.ASTCDInterface + && incarnation + instanceof de.monticore.cdinterfaceandenum._ast.ASTCDInterface) + || (reference instanceof de.monticore.cdinterfaceandenum._ast.ASTCDEnum + && incarnation instanceof de.monticore.cdinterfaceandenum._ast.ASTCDEnum); } + + private static Optional groupingName( + IncarnationContext context, String concreteTypeName) { + return context + .getGroupingFor(StableElementKey.type(concreteTypeName)) + .map(grouping -> grouping.key().getName()); + } + } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapterTool.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapterTool.java index 14666089..b3fc60be 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapterTool.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapterTool.java @@ -1,102 +1,206 @@ package de.monticore.codeAdaption; +import static de.monticore.cdconformance.CDConfParameter.ADAPTED_NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.ALLOW_ADDITIONAL_PARAMETERS; +import static de.monticore.cdconformance.CDConfParameter.ALLOW_CARD_RESTRICTION; +import static de.monticore.cdconformance.CDConfParameter.INHERITANCE; +import static de.monticore.cdconformance.CDConfParameter.METHOD_OVERLOADING; +import static de.monticore.cdconformance.CDConfParameter.NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.SRC_TARGET_ASSOC_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STEREOTYPE_MAPPING; +import static de.monticore.codeAdaption.utils.AdapterParam.ANNOTATION_MATCHING; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_TYPE; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_TYPE_MEMBER; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_VAR; +import static de.monticore.codeAdaption.utils.AdapterParam.INFIX_MATCHING; +import static de.monticore.codeAdaption.utils.AdapterParam.NAME_MATCHING; + import de.monticore.CD4CodeTool; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.AdapterParam; +import de.monticore.codeAdaption.utils.JavaLoader; import de.se_rwth.commons.logging.Log; -import java.util.*; -import org.apache.commons.cli.*; +import java.io.File; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.Set; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +/** Command-line entry point for reference-code adaptation. */ public class CodeAdapterTool extends CD4CodeTool { - /** - * Processes user input from command line and delegates to the corresponding tools. - * - * @param args The input parameters for configuring the OCL tool. - */ + public static void main(String[] args) { + int exitCode = new CodeAdapterTool().execute(args); + if (exitCode != 0) { + System.exit(exitCode); + } + } + @Override public void run(String[] args) { - init(); - Options options = initOptions(); - /* - java - jar AdapterTool . jar -i " University . cd " \ - 2 -- reference " UserRole . cd " -- rc " code " - */ + execute(args); + } + /** Executes one CLI invocation and returns a process-style exit code. */ + int execute(String[] args) { + init(); + Options options = addAdditionalOptions(new Options()); + if (Arrays.stream(args).anyMatch(argument -> "-h".equals(argument) || "--help".equals(argument))) { + printAdapterHelp(options); + return 0; + } try { - // create CLI parser and parse input options from command line - CommandLineParser cliparser = new DefaultParser(); - CommandLine cmd = cliparser.parse(options, args); - - if (cmd.hasOption("i")) { - // -option developer logging - if (cmd.hasOption("d")) { - Log.initDEBUG(); - } else { - Log.init(); - } + CommandLine commandLine = new DefaultParser().parse(options, args); + if (commandLine.hasOption("debug")) { + Log.initDEBUG(); + } else { + Log.init(); } - } catch (ParseException e) { - Log.error("0xA7101 Could not process CLI parameters: " + e.getMessage()); + Set mappings = values(commandLine, "mapping"); + if (mappings.isEmpty()) { + throw new ParseException("At least one --mapping must be supplied"); + } + + Set adapterParameters = matchingParameters(commandLine); + if (commandLine.hasOption("ignore-unmatched")) { + adapterParameters.add(IGNORE_NON_MATCHED_TYPE); + adapterParameters.add(IGNORE_NON_MATCHED_TYPE_MEMBER); + adapterParameters.add(IGNORE_NON_MATCHED_VAR); + } + + CodeAdapter adapter = new CodeAdapter(adapterParameters, defaultConformanceParameters()); + adapter.adapt( + requiredFile(commandLine, "reference"), + requiredFile(commandLine, "concrete"), + mappings, + requiredPath(commandLine, "reference-code"), + requiredPath(commandLine, "concrete-code"), + requiredPath(commandLine, "output"), + commandLine.hasOption("concretize"), + !commandLine.hasOption("no-common-parent")); + return 0; + } catch (ParseException | IllegalArgumentException | CodeAdaptationException exception) { + Log.warn("Code adaptation failed: " + exception.getMessage()); + printAdapterHelp(options); + return 2; + } catch (RuntimeException exception) { + Log.warn("Unexpected code-adaptation failure: " + exception.getMessage()); + return 1; } } - /*=================================================================*/ - /* Part 2: Executing arguments - /*=================================================================*/ - - /** - * Parses the contents of a given file as OCL. - * - * @param path The path to the OCL-file as String - * @return parsed AST - */ @Override public ASTCDCompilationUnit parse(String path) { - return null; + return JavaLoader.parseCD(path); } - /** - * Initializes the additional options for the OCL tool. - * - * @return The CLI options with arguments. - */ @Override public Options addAdditionalOptions(Options options) { - - // accept VariableSymbols - Option varSymbols = - Option.builder("i") - .longOpt("concrete") - .optionalArg(false) - .argName("concrete class diagram") - .hasArgs() - .desc("introduce the concrete class diagram") - .build(); - options.addOption(varSymbols); - - // accept FunctionSymbols - Option funcSymbols = - Option.builder("rc") - .longOpt("reference-code") - .optionalArg(false) - .argName("reference-code") + options.addOption(requiredPathOption("r", "reference", "reference class diagram")); + options.addOption(requiredPathOption("c", "concrete", "concrete class diagram")); + options.addOption(requiredPathOption("rc", "reference-code", "reference Java source directory")); + options.addOption(requiredPathOption("cc", "concrete-code", "concrete Java source directory")); + options.addOption(requiredPathOption("o", "output", "generated Java output directory")); + options.addOption( + Option.builder("m") + .longOpt("mapping") .hasArgs() - .desc("Introduce the reference code.") - .build(); - options.addOption(funcSymbols); - - // accept FunctionSymbols - Option ignoreSymbols = - Option.builder("r") - .longOpt("reference") - .optionalArg(false) - .argName("reference class diagram") + .argName("name...") + .desc("mapping stereotype name; at least one is required") + .build()); + options.addOption( + Option.builder() + .longOpt("matching") .hasArgs() - .desc("introduce the reference class diagram") - .build(); - options.addOption(ignoreSymbols); - + .argName("name|infix|annotation") + .desc("matching strategies; defaults to all strategies") + .build()); + options.addOption( + Option.builder().longOpt("concretize").desc("complete the concrete CD first").build()); + options.addOption( + Option.builder() + .longOpt("no-common-parent") + .desc("disable common-parent grouping for multiple incarnations") + .build()); + options.addOption( + Option.builder() + .longOpt("ignore-unmatched") + .desc("retain unmatched reference-code elements instead of reporting them") + .build()); + options.addOption(Option.builder("d").longOpt("debug").desc("enable debug logging").build()); + options.addOption(Option.builder("h").longOpt("help").desc("show this help").build()); return options; } + + private static Option requiredPathOption(String shortName, String longName, String description) { + return Option.builder(shortName) + .longOpt(longName) + .hasArg() + .required() + .argName("path") + .desc(description) + .build(); + } + + private static File requiredFile(CommandLine commandLine, String option) throws ParseException { + return requiredPath(commandLine, option).toFile(); + } + + private static Path requiredPath(CommandLine commandLine, String option) throws ParseException { + String value = commandLine.getOptionValue(option); + if (value == null || value.isBlank()) { + throw new ParseException("Missing required option --" + option); + } + return Path.of(value).toAbsolutePath().normalize(); + } + + private static Set values(CommandLine commandLine, String option) { + String[] supplied = commandLine.getOptionValues(option); + return supplied == null + ? new LinkedHashSet<>() + : new LinkedHashSet<>(Arrays.asList(supplied)); + } + + private static Set matchingParameters(CommandLine commandLine) + throws ParseException { + Set requested = values(commandLine, "matching"); + if (requested.isEmpty()) { + return new LinkedHashSet<>(Set.of(NAME_MATCHING, INFIX_MATCHING, ANNOTATION_MATCHING)); + } + Set result = new LinkedHashSet<>(); + for (String value : requested) { + switch (value.toLowerCase(Locale.ROOT)) { + case "name" -> result.add(NAME_MATCHING); + case "infix" -> result.add(INFIX_MATCHING); + case "annotation" -> result.add(ANNOTATION_MATCHING); + default -> throw new ParseException("Unknown matching strategy: " + value); + } + } + return result; + } + + private static Set defaultConformanceParameters() { + return Set.of( + STEREOTYPE_MAPPING, + NAME_MAPPING, + SRC_TARGET_ASSOC_MAPPING, + INHERITANCE, + ALLOW_CARD_RESTRICTION, + METHOD_OVERLOADING, + ADAPTED_NAME_MAPPING, + ALLOW_ADDITIONAL_PARAMETERS); + } + + private static void printAdapterHelp(Options options) { + new HelpFormatter().printHelp("java -jar CodeAdapter.jar", options, true); + } } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/MappingAdaptationRunner.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/MappingAdaptationRunner.java new file mode 100644 index 00000000..c40c7b35 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/MappingAdaptationRunner.java @@ -0,0 +1,155 @@ +package de.monticore.codeAdaption; + +import de.monticore.cdconformance.CDConformanceChecker; +import de.monticore.codeAdaption.handler.BasicUpdateHandler; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.updater.CodeUpdater; +import de.monticore.codeAdaption.updater.CodeUpdaterMill; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.validator.CodeValidator; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** Executes the complete isolated updater lifecycle for one mapping's adaptation passes. */ +final class MappingAdaptationRunner { + /** + * One deterministic multi-incarnation choice and the top-level Java types retained from it. + * + *

{@code typeSelection} maps reference type keys to the one concrete incarnation used by this + * pass, for example {@code Payment -> CreditCard}. {@code outputTypeNames} contains concrete Java + * top-level names such as {@code CreditCardAdapter}; all other transformed units are discarded + * after serving as cross-file resolution context. + */ + record AdaptationPass( + Map typeSelection, + Set outputTypeNames) { + AdaptationPass { + typeSelection = Map.copyOf(typeSelection); + outputTypeNames = Set.copyOf(outputTypeNames); + } + + String describeSelection() { + return typeSelection.entrySet().stream() + .sorted(Map.Entry.comparingByKey(Comparator.comparing(StableElementKey::signature))) + .map(entry -> entry.getKey().signature() + "=" + entry.getValue().key().signature()) + .collect(Collectors.joining(", ", "[", "]")); + } + } + + private final AdaptationWorkspace workspace; + private final AdaptedCodeMerger codeMerger; + private final Path stagingPath; + private final CDModelIndex referenceIndex; + private final CDModelIndex concreteIndex; + private final CDModelIndex inputConcreteIndex; + private final boolean useCommonParentForMultipleIncarnations; + + MappingAdaptationRunner( + AdaptationWorkspace workspace, + AdaptedCodeMerger codeMerger, + Path stagingPath, + CDModelIndex referenceIndex, + CDModelIndex concreteIndex, + CDModelIndex inputConcreteIndex, + boolean useCommonParentForMultipleIncarnations) { + this.workspace = workspace; + this.codeMerger = codeMerger; + this.stagingPath = stagingPath; + this.referenceIndex = referenceIndex; + this.concreteIndex = concreteIndex; + this.inputConcreteIndex = inputConcreteIndex; + this.useCommonParentForMultipleIncarnations = + useCommonParentForMultipleIncarnations; + } + + /** + * Runs every planned pass for one mapping and merges the retained output units. + * + * @param mapping stereotype name identifying the isolated incarnation context + * @param mappingCode complete filtered source set loaded into every pass for cross-file resolution + * @param passes concrete incarnation selections to execute + * @param checker usable conformance checker, or {@code null} for manual mapping + * @param validator matcher/validation state for the same mapping + * @param context reference-element to concrete-incarnation mappings for this mapping only + * @param groupingMappings incarnation simple name to common grouping-type simple name + */ + Set run( + String mapping, + Set mappingCode, + List passes, + CDConformanceChecker checker, + CodeValidator validator, + IncarnationContext context, + Map groupingMappings) { + Set adaptedCode = new LinkedHashSet<>(); + for (AdaptationPass pass : passes) { + // Load the complete mapping source set so Spoon can update cross-file references. The pass + // still controls which transformed top-level types are retained below. + Set mappingRefCode = cloneUnits(mappingCode); + Path tempPath = workspace.createMappingDirectory(stagingPath); + try { + JavaLoader.printAST(mappingRefCode, tempPath); + CodeUpdater updater = prepareUpdater(tempPath, groupingMappings); + BasicUpdateHandler handler = + new BasicUpdateHandler( + referenceIndex, + concreteIndex, + inputConcreteIndex, + checker, + updater, + validator, + context, + pass.typeSelection(), + useCommonParentForMultipleIncarnations); + + handler.handleUpdate(mappingRefCode); + updater.printCode(); + Set processedCode = + codeMerger.splitCompilationUnitsByType(JavaLoader.readJavaCode(tempPath)); + processedCode = + processedCode.stream() + .filter( + unit -> + unit.getTypeDeclarationList().stream() + .anyMatch(type -> pass.outputTypeNames().contains(type.getName()))) + .collect(Collectors.toCollection(LinkedHashSet::new)); + adaptedCode = codeMerger.mergeAdaptedCode(adaptedCode, processedCode); + } catch (RuntimeException | AssertionError exception) { + String selection = + pass.typeSelection().isEmpty() + ? "" + : " for type selection " + pass.describeSelection(); + throw new CodeAdaptationException( + "Failed to process mapping '" + mapping + "'" + selection, exception); + } finally { + CodeUpdaterMill.reset(); + workspace.discard(tempPath); + } + } + return adaptedCode; + } + + private CodeUpdater prepareUpdater(Path tempPath, Map groupingMappings) { + CodeUpdaterMill.reset(); + CodeUpdater updater = CodeUpdaterMill.getUpdater(); + updater.setCodePath(tempPath); + updater.setGroupingMappings(groupingMappings); + updater.setOutputDirectory(tempPath); + return updater; + } + + private static Set cloneUnits( + Set units) { + Set clones = new LinkedHashSet<>(); + units.forEach(unit -> clones.add(unit.deepClone())); + return clones; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/OutputCodeService.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/OutputCodeService.java new file mode 100644 index 00000000..32634007 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/OutputCodeService.java @@ -0,0 +1,106 @@ +package de.monticore.codeAdaption; + +import de.monticore.codeAdaption.updater.CodeUpdater; +import de.monticore.codeAdaption.updater.CodeUpdaterMill; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Handles final generated-source cleanup and inclusion of pre-existing concrete handwritten files. + * + *

Adapted files are already present in the staging output. Concrete handwritten files are added + * only when no adapted file occupies their target path, so adapted output wins without overwriting + * the user's concrete source tree. + */ +final class OutputCodeService { + + /** + * Copies concrete handwritten files into their final package-relative output locations. + * + *

Java files are placed according to their declared package rather than their input folder. + * For example, {@code misc/Port.java} declaring {@code package shipping;} targets {@code + * shipping/Port.java}. Non-Java files preserve their path relative to {@code conHwcPath}. If two + * inputs target the same output path, identical content is deduplicated and differing content is + * rejected. + */ + void copyConcreteFiles(Path conHwcPath, Path outputPath) { + if (!Files.exists(conHwcPath)) { + try { + Files.createDirectories(outputPath); + } catch (IOException e) { + throw new IllegalStateException("Failed to create output directory " + outputPath, e); + } + return; + } + try (var paths = Files.walk(conHwcPath)) { + Map sourcesByTarget = new LinkedHashMap<>(); + for (Path source : + paths + .filter(Files::isRegularFile) + .sorted(java.util.Comparator.comparing(Path::toString)) + .toList()) { + Path target = concreteCopyTarget(conHwcPath, source, outputPath).toAbsolutePath().normalize(); + Path existingSource = sourcesByTarget.putIfAbsent(target, source); + if (existingSource != null && Files.mismatch(existingSource, source) != -1L) { + throw new IllegalStateException( + "Concrete files '" + + existingSource + + "' and '" + + source + + "' both target '" + + target + + "' but have different content"); + } + } + for (Map.Entry entry : sourcesByTarget.entrySet()) { + Path target = entry.getKey(); + Path source = entry.getValue(); + Files.createDirectories(target.getParent()); + if (!Files.exists(target)) { + Files.copy(source, target); + } + } + } catch (IOException e) { + throw new IllegalStateException("Failed to include concrete handwritten code", e); + } + } + + /** Removes adapter-only annotations/imports and performs the updater's final source cleanup. */ + void cleanCode(Path codePath) { + CodeUpdaterMill.reset(); + try { + CodeUpdater updater = CodeUpdaterMill.getUpdater(); + updater.cleanCode(codePath); + } finally { + CodeUpdaterMill.reset(); + } + } + + private Path concreteCopyTarget(Path conHwcPath, Path source, Path outputPath) { + if (!source.toString().endsWith(".java")) { + return outputPath.resolve(conHwcPath.relativize(source)); + } + try { + ASTOrdinaryCompilationUnit ast = JavaLoader.loadJava(source.toFile()); + if (ast.isPresentPackageDeclaration()) { + Path packagePath = + Path.of( + ast.getPackageDeclaration() + .getMCQualifiedName() + .getQName() + .replace('.', File.separatorChar)); + return outputPath.resolve(packagePath).resolve(source.getFileName()); + } + } catch (RuntimeException | AssertionError parseFailure) { + throw new IllegalStateException( + "Failed to determine package for concrete Java file " + source, parseFailure); + } + return outputPath.resolve(conHwcPath.relativize(source)); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/AdaptationContextFactory.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/AdaptationContextFactory.java new file mode 100644 index 00000000..e3f84146 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/AdaptationContextFactory.java @@ -0,0 +1,128 @@ +package de.monticore.codeAdaption.context; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.cdconformance.CDConformanceChecker; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContextBuilder; +import de.monticore.codeAdaption.handler.multiIncarnation.ManualIncarnationContextBuilder; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.se_rwth.commons.logging.Log; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +/** + * Builds one incarnation context per requested mapping stereotype. + * + *

For example, mappings {@code [shop, billing]} produce a result map whose keys are {@code + * shop} and {@code billing}. Each value contains only the incarnations derived for that mapping; + * mappings are never combined into one context. + */ +public final class AdaptationContextFactory { + + private final Set confParams; + private final MappingConformanceService conformanceService; + + public AdaptationContextFactory( + Set confParams, MappingConformanceService conformanceService) { + this.confParams = Set.copyOf(confParams); + this.conformanceService = conformanceService; + } + + /** + * Builds mapping-name to adaptation-result entries in deterministic mapping-name order. + * + *

If {@code useConcretizationMappings} is {@code false}, every context is derived directly + * from stereotypes and deterministic name matches; the result has no checker. If it is {@code + * true}, each mapping is first checked independently. A successful checker result is retained + * only when it also supplies an incarnation mapping. Otherwise that one mapping falls back to + * manual derivation while other mappings may still use their checker results. + * + * @param referenceIndex indexed reference CD whose elements become mapping keys + * @param concreteIndex indexed concrete CD whose elements become incarnations + * @param mappings stereotype names to evaluate, for example {@code shop} and {@code billing} + * @param useConcretizationMappings whether to prefer usable conformance-checker incarnation + * mappings over manual stereotype derivation + * @return mapping stereotype name to its isolated context, optional checker, and checker-mapping + * availability flag + */ + public Map buildResults( + CDModelIndex referenceIndex, + CDModelIndex concreteIndex, + Set mappings, + boolean useConcretizationMappings) { + + ASTCDCompilationUnit refCD = referenceIndex.cd(); + ASTCDCompilationUnit conCD = concreteIndex.cd(); + + Map results = new LinkedHashMap<>(); + + if (!useConcretizationMappings) { + ManualIncarnationContextBuilder builder = + new ManualIncarnationContextBuilder(referenceIndex, concreteIndex, confParams); + mappings.stream() + .sorted() + .forEach( + mapping -> + results.put( + mapping, + new AdaptationContextResult( + builder.buildContextForMapping(mapping), null, false))); + return results; + } + + for (String mapping : mappings.stream().sorted().toList()) { + CDConformanceChecker checker = conformanceService.newChecker(); + boolean mappingValid = conformanceService.checkOrFalse(checker, conCD, refCD, mapping); + + if (!mappingValid) { + Log.warn( + "Mapping '" + + mapping + + "' failed conformance check - will use conflict-checked stereotype-based fallback for this mapping"); + } else { + Log.info( + "Mapping '" + + mapping + + "' passed conformance check with incarnation mapping: " + + (checker.getIncarnationMapping() != null + ? checker.getIncarnationMapping().getClass().getSimpleName() + : "null"), + "CodeAdapter"); + } + + boolean conformanceMappingAvailable = + mappingValid && checker.getIncarnationMapping() != null; + IncarnationContext context; + if (!conformanceMappingAvailable) { + context = + new ManualIncarnationContextBuilder(referenceIndex, concreteIndex, confParams) + .buildContextForMapping(mapping); + } else { + IncarnationContextBuilder builder = + new IncarnationContextBuilder(checker, referenceIndex, concreteIndex); + context = builder.buildContextForMapping(mapping, false); + } + results.put( + mapping, + new AdaptationContextResult( + context, + conformanceMappingAvailable ? checker : null, + conformanceMappingAvailable)); + } + + return results; + } + + /** + * Result for one mapping stereotype. + * + * @param context incarnations used by adaptation; always present, including after manual fallback + * @param checker checker retained only when it produced the context's usable incarnation mapping + * @param conformanceValid whether a usable conformance-checker incarnation mapping produced this + * context; {@code false} also covers a successful check that exposed no incarnation mapping + */ + public record AdaptationContextResult( + IncarnationContext context, CDConformanceChecker checker, boolean conformanceValid) {} +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/ConcretizationService.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/ConcretizationService.java new file mode 100644 index 00000000..de5006f5 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/ConcretizationService.java @@ -0,0 +1,66 @@ +package de.monticore.codeAdaption.context; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdconcretization.ConcretizationCompleter; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.se_rwth.commons.logging.Log; +import java.util.ArrayList; +import java.util.Set; + +/** Wraps cdconcretization setup and fail-quick handling for adaptation runs. */ +public final class ConcretizationService { + + private final Set confParams; + + public ConcretizationService(Set confParams) { + this.confParams = Set.copyOf(confParams); + } + + public ASTCDCompilationUnit completeConcreteCD( + ASTCDCompilationUnit conCD, ASTCDCompilationUnit refCD, Set mappings) { + ConcretizationCompleter completer = new ConcretizationCompleter(confParams); + ASTCDCompilationUnit completedCD = conCD.deepClone(); + JavaLoader.initializeCDSymbolTable(completedCD); + synchronized (Log.class) { + boolean failQuickEnabled = Log.isFailQuickEnabled(); + int findingsBefore = Log.getFindings().size(); + long errorsBefore = Log.getErrorCount(); + try { + Log.enableFailQuick(false); + ArrayList orderedMappings = new ArrayList<>(mappings); + orderedMappings.sort(String::compareTo); + completer.completeCD(completedCD, refCD, orderedMappings); + // Completion mutates the cloned AST by adding and repairing model elements. Rebuild its + // symbols before conformance/context construction so added fields, methods, types and + // inheritance relationships are visible through the same completed snapshot. + JavaLoader.initializeCDSymbolTable(completedCD); + if (Log.getErrorCount() > errorsBefore) { + String diagnostics = + Log.getFindings().subList(findingsBefore, Log.getFindings().size()).stream() + .map(finding -> finding.getMsg()) + .distinct() + .reduce((left, right) -> left + "; " + right) + .orElse("unknown concretization error"); + throw new IllegalStateException( + "CD concretization reported errors; adaptation cannot continue safely: " + + diagnostics); + } + Log.info("Concretized concrete CD before code adaptation", "CodeAdapter"); + return completedCD; + } catch (Exception | AssertionError throwable) { + throw new IllegalStateException( + "CD concretization failed before code adaptation; the concrete CD was not modified", + throwable); + } finally { + // Log.enableFailQuick(true) terminates the process when error findings exist. The errors + // produced by this guarded dependency call are represented by the exception above, so + // remove only those new findings before restoring the caller's global logging policy. + if (Log.getErrorCount() > errorsBefore && Log.getFindings().size() > findingsBefore) { + Log.getFindings().subList(findingsBefore, Log.getFindings().size()).clear(); + } + Log.enableFailQuick(failQuickEnabled); + } + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/GroupingMappingService.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/GroupingMappingService.java new file mode 100644 index 00000000..9e80a12c --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/GroupingMappingService.java @@ -0,0 +1,64 @@ +package de.monticore.codeAdaption.context; + +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Derives Java type-name replacements for groups of concrete incarnations. + * + *

An incarnation is a concrete CD type to which a reference type is mapped. If one reference + * type has several incarnations, those incarnations form an incarnation group. Java declarations + * that must work for the entire group cannot use the type of only one incarnation. They instead + * use a common class or interface from the concrete CD that represents the group; this class calls + * that common type the grouping type. + */ +public final class GroupingMappingService { + + /** + * Computes replacements for one mapping only, preventing grouping decisions from leaking into + * another mapping. + * + *

Each entry maps the simple type name of one concrete incarnation to the simple name of the + * common type representing its incarnation group. The code updater uses these replacements in + * shared declarations such as fields, parameters, return types, and collection element types, so + * that the resulting Java declaration can hold or accept every incarnation in the group. + * + *

For example, assume the reference type {@code Payment} has the concrete incarnations {@code + * CreditCard} and {@code Invoice}. If both are represented by the common concrete interface + * {@code PaymentMethod}, this method returns {@code {CreditCard=PaymentMethod, + * Invoice=PaymentMethod}}. A shared parameter can then be written as {@code PaymentMethod payment} + * instead of being tied to only {@code CreditCard} or {@code Invoice}. + * + *

Identity replacements, such as {@code PaymentMethod -> PaymentMethod}, are omitted because + * they do not require a Java type rewrite. + * + * @param context the mapping-local incarnation and grouping context + * @return insertion-ordered incarnation-simple-name to grouping-type-simple-name replacements + * @throws IllegalStateException if one incarnation simple name resolves to different grouping + * types + */ + public Map compute(IncarnationContext context) { + Map result = new LinkedHashMap<>(); + context.getGroupingMappings().entrySet().stream() + .sorted(Map.Entry.comparingByKey(java.util.Comparator.comparing(key -> key.signature()))) + .forEach( + entry -> { + String concrete = entry.getKey().getName(); + String grouping = entry.getValue().key().getName(); + if (!grouping.equals(concrete)) { + putUnambiguous(result, concrete, grouping); + } + }); + return result; + } + + /** Adds one incarnation-to-grouping-type rewrite while rejecting ambiguous simple names. */ + private static void putUnambiguous(Map result, String concrete, String grouping) { + String previous = result.putIfAbsent(concrete, grouping); + if (previous != null && !previous.equals(grouping)) { + throw new IllegalStateException( + "Ambiguous grouping for concrete type '" + concrete + "': '" + previous + "' and '" + grouping + "'"); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/MappingConformanceService.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/MappingConformanceService.java new file mode 100644 index 00000000..97ff9e2d --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/context/MappingConformanceService.java @@ -0,0 +1,65 @@ +package de.monticore.codeAdaption.context; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.cdconformance.CDConformanceChecker; +import de.se_rwth.commons.logging.Log; +import java.util.List; +import java.util.Set; + +/** Creates and runs conformance checkers with the adapter's fail-quick policy. */ +public final class MappingConformanceService { + + private final Set confParams; + + public MappingConformanceService(Set confParams) { + this.confParams = Set.copyOf(confParams); + } + + public CDConformanceChecker newChecker() { + return new CDConformanceChecker(confParams); + } + + public boolean checkOrFalse( + CDConformanceChecker checker, + ASTCDCompilationUnit conCD, + ASTCDCompilationUnit refCD, + String mapping) { + boolean valid = false; + Throwable failure = null; + List diagnostics; + synchronized (Log.class) { + boolean failQuickEnabled = Log.isFailQuickEnabled(); + int findingsBefore = Log.getFindings().size(); + try { + Log.enableFailQuick(false); + valid = checker.checkConformance(conCD, refCD, mapping); + } catch (RuntimeException | AssertionError throwable) { + failure = throwable; + } finally { + diagnostics = + Log.getFindings().subList(findingsBefore, Log.getFindings().size()).stream() + .map(finding -> finding.getMsg()) + .distinct() + .toList(); + // The guarded dependency call is represented by the boolean result and diagnostics below. + // Do not leak its findings into the caller's process-global logging state. + Log.getFindings().subList(findingsBefore, Log.getFindings().size()).clear(); + Log.enableFailQuick(failQuickEnabled); + } + } + if (failure != null) { + Log.warn( + "Conformance checker threw during check for mapping '" + + mapping + + "': " + + failure.getMessage() + + " - will use validated stereotype-based fallback"); + } + diagnostics.forEach( + diagnostic -> + Log.warn( + "Conformance check for mapping '" + mapping + "': " + diagnostic)); + return valid; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/BasicUpdateHandler.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/BasicUpdateHandler.java index 8a325491..b08e811e 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/BasicUpdateHandler.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/BasicUpdateHandler.java @@ -1,69 +1,80 @@ package de.monticore.codeAdaption.handler; -import de.monticore.cdbasis._ast.ASTCDAttribute; -import de.monticore.cdbasis._ast.ASTCDCompilationUnit; -import de.monticore.cdbasis._ast.ASTCDType; import de.monticore.cdbasis._symboltable.CDTypeSymbol; import de.monticore.cdconformance.CDConformanceChecker; -import de.monticore.cddiff.CDDiffUtil; -import de.monticore.codeAdaption.matcher.*; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.matcher.CodeMatching; import de.monticore.codeAdaption.updater.CodeUpdater; +import de.monticore.codeAdaption.utils.CDModelIndex; import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; import de.monticore.codeAdaption.validator.CodeValidator; import de.monticore.java.javadsl.JavaDSLMill; -import de.monticore.java.javadsl._ast.ASTFieldDeclaration; -import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; -import de.monticore.java.javadsl._ast.ASTTypeDeclaration; import de.monticore.java.javadsl._visitor.JavaDSLTraverser; -import de.monticore.javalight._ast.ASTMethodDeclaration; -import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; import de.monticore.symbols.oosymbols._symboltable.FieldSymbol; import de.monticore.symboltable.ISymbol; -import de.monticore.types.mcbasictypes._ast.ASTMCType; -import java.nio.file.Path; -import java.util.*; -// TODO: 20.09.2023 handle concrete handwritten-code - -/*** - * this class is to handle is to handle the update operation. - * - - * 1- iterate over all adaptable code-elements (Type, field, method,local variable,formal parameters-names). - * 2- get the match of each element in the reference class diagram. - * 3- compute the concrete value of each element form the matching using the conformance checker. - * 4- use the updater to update the value in the code. - * - - * this handler assumes that each reference element has a unique incarnation. - */ -public class BasicUpdateHandler { - protected ASTCDCompilationUnit conCD; - protected ASTCDCompilationUnit refCD; - protected CDConformanceChecker checker; - protected CodeUpdater updater; - - protected CodeValidator validator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** Coordinates the CD-based adaptation of Java AST elements. */ +public final class BasicUpdateHandler { + final CDModelIndex conIndex; + final CDModelIndex inputConIndex; + final CDModelIndex refIndex; + final CDConformanceChecker checker; + final CodeUpdater updater; + final CodeValidator validator; + + /** Optional incarnation context for stereotype-based mapping when conformance is skipped. */ + final IncarnationContext incarnationContext; + + /** Stable concrete choices for the current isolated pass. Empty for the ordinary case. */ + final Map incarnationSelection; + + final boolean useCommonParentForMultipleIncarnations; + + private final ConcreteSymbolResolver symbolResolver; + private final JavaMemberUpdateService memberUpdates; + private final JavaTypeUpdateService typeUpdates; public BasicUpdateHandler( - ASTCDCompilationUnit refCD, - ASTCDCompilationUnit conCD, - Path conHwcPath, + CDModelIndex refIndex, + CDModelIndex conIndex, + CDModelIndex inputConIndex, CDConformanceChecker checker, CodeUpdater updater, - CodeValidator validator) { + CodeValidator validator, + IncarnationContext incarnationContext, + Map incarnationSelection, + boolean useCommonParentForMultipleIncarnations) { this.updater = updater; this.checker = checker; - this.conCD = conCD; - this.refCD = refCD; + this.conIndex = conIndex; + this.inputConIndex = inputConIndex; + this.refIndex = refIndex; this.validator = validator; + this.incarnationContext = incarnationContext; + this.incarnationSelection = Map.copyOf(incarnationSelection); + this.useCommonParentForMultipleIncarnations = useCommonParentForMultipleIncarnations; + this.symbolResolver = + new ConcreteSymbolResolver(this, refIndex.cd(), conIndex.cd()); + this.memberUpdates = + new JavaMemberUpdateService(validator, updater, refIndex, conIndex, symbolResolver); + this.typeUpdates = new JavaTypeUpdateService(this, symbolResolver, memberUpdates); } public void handleUpdate(Set javaFiles) { + validateIncarnationContext(); + typeUpdates.beginRun(); + validator.initializeTypeMatcher(javaFiles); - // Collect elements of each type Set typeElements = new LinkedHashSet<>(); for (ASTOrdinaryCompilationUnit ast : javaFiles) { - - // collect code elements JavaAstElemCollector collector = new JavaAstElemCollector(); JavaDSLTraverser traverser = JavaDSLMill.traverser(); traverser.add4JavaDSL(collector); @@ -71,126 +82,79 @@ public void handleUpdate(Set javaFiles) { typeElements.add(collector); } - // update local variable and method parameters - typeElements.forEach(this::handleVariableUpdate); - - // update methods and attributes - typeElements.forEach(this::handleTMemberUpdate); - - // update types - typeElements.forEach(this::handleTypeUpdate); - + typeElements.forEach(memberUpdates::handleVariableUpdate); + typeElements.forEach(memberUpdates::handleMemberUpdate); + typeElements.forEach(memberUpdates::handleAssociationRoleUpdate); + typeElements.forEach(typeUpdates::handleTypeUpdate); + typeElements.forEach(typeUpdates::projectCompletedMembers); updater.printCode(); } - protected void handleTypeUpdate(JavaAstElemCollector collector) { - // update type present in the reference code - for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { - Optional matching = validator.getMatchedType(type); - if (matching.isPresent() && matching.get().mustBePerform()) { - String newName = buildConcreteName(matching.get()); - updater.updateType(type, newName); - } - } - - // update type not present in the reference code - for (ASTCDType cdType : CDDiffUtil.getAllCDTypes(refCD)) { - String newName = getConTypeSymbol(cdType.getSymbol()).getName(); - updater.updateCDType(cdType, newName); + private void validateIncarnationContext() { + if (incarnationContext == null) { + return; } - } - - protected void handleTMemberUpdate(JavaAstElemCollector collector) { - for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { - - // update method names - for (ASTMethodDeclaration method : collector.getAllMethodDeclarations(type)) { - Optional matching = validator.getMatchedMethod(type, method); - if (matching.isPresent() && matching.get().mustBePerform()) { - String newName = buildConcreteName(matching.get()); - updater.updateMethod(type, method, newName); - } + for (Map.Entry> entry : + incarnationContext.getMappings().entrySet()) { + if (entry.getKey().getKind() == StableElementKey.Kind.METHOD + && entry.getValue().stream().map(value -> value.key().signature()).distinct().count() + != entry.getValue().size()) { + throw new IllegalStateException( + "Conflicting method incarnations for " + entry.getKey().signature()); } - - // update type parameters names - for (ASTFieldDeclaration field : collector.getAllFieldDeclarations(type)) { - Optional matching = validator.getMatchedField(type, field); - if (matching.isPresent() && matching.get().mustBePerform()) { - String newName = buildConcreteName(matching.get()); - updater.updateField(type, field, newName); - } + if (entry.getKey().getKind() != StableElementKey.Kind.FIELD) { + continue; } - - // update type parameters names - for (ASTMCType supertype : collector.getAllFSuperTypeDeclarations(type)) { - Optional matching = validator.getMatchedSupertype(type, supertype); - if (matching.isPresent() && matching.get().mustBePerform()) { - String newName = buildConcreteName(matching.get()); - updater.updateSuperType(type, supertype, newName); + Map ownersAndTypes = new LinkedHashMap<>(); + for (IncarnationContext.MappedElement mapped : entry.getValue()) { + StableElementKey target = mapped.key(); + String ownerAndName = target.getOwnerType().orElse("") + "." + target.getName(); + String fieldKind = target.getFieldKind().orElse(""); + String previous = ownersAndTypes.putIfAbsent(ownerAndName, fieldKind); + if (previous != null && !previous.equals(fieldKind)) { + throw new IllegalStateException( + "Conflicting field incarnations for " + entry.getKey().signature()); } } } } - protected void handleVariableUpdate(JavaAstElemCollector collector) { - for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { - for (ASTMethodDeclaration method : collector.getAllMethodDeclarations(type)) { - - // update local variables - for (ASTLocalVariableDeclaration var : collector.getAllLocVariables(type, method)) { - Optional matching = validator.getMatchedLocalVariable(type, method, var); - if (matching.isPresent() && matching.get().mustBePerform()) { - String newName = buildConcreteName(matching.get()); - updater.updateLocalVariable(type, method, var, newName); - } - } + /** Builds the concrete name for an element from the references in its matching. */ + String buildConcreteName(CodeMatching matching) { + return symbolResolver.buildConcreteName(matching); + } - // update all formal parameters - for (ASTFormalParameter param : collector.getAllParameters(type, method)) { - Optional matching = validator.getMatchedParameter(type, method, param); - if (matching.isPresent() && matching.get().mustBePerform()) { - String newName = buildConcreteName(matching.get()); - updater.updateMethodParameter(type, method, param, newName); - } - } - } - } + /** Resolves a reference symbol from the optional incarnation context. */ + Optional getSymbolFromContext(ISymbol refSymbol) { + return symbolResolver.getSymbolFromContext(refSymbol); } - /*** - * build concrete name of an element form the matching found in the class diagram - */ - private String buildConcreteName(CodeMatching codeMatching) { - List conReferences = new ArrayList<>(); - - // resolve concrete references - for (ISymbol refSymbol : codeMatching.getReferences()) { - if (refSymbol instanceof CDTypeSymbol) { - conReferences.add(getConTypeSymbol((CDTypeSymbol) refSymbol)); - } else { - conReferences.add(getConAttributeSymbol((FieldSymbol) refSymbol)); - } + Optional referenceKey(ISymbol symbol) { + return StableElementKey.fromSymbol(symbol, refIndex); + } + + Optional concreteKey(ISymbol symbol) { + return StableElementKey.fromSymbol(symbol, conIndex); + } + + List mappedIncarnations(ISymbol reference) { + if (incarnationContext == null) { + return List.of(); } - // fill the template with the references - return MatcherHelper.fillTemplate(codeMatching.getTemplate(), conReferences); + return referenceKey(reference) + .map(incarnationContext::getIncarnations) + .orElseGet(List::of); } - protected ISymbol getConTypeSymbol(CDTypeSymbol symbol) { - return checker - .getIncarnationMapping() - .getIncarnations(symbol.getAstNode()) - .iterator() - .next() - .getSymbol(); + ISymbol getConTypeSymbol(CDTypeSymbol symbol) { + return symbolResolver.getConTypeSymbol(symbol); } - protected ISymbol getConAttributeSymbol(FieldSymbol symbol) { + ISymbol getConAttributeSymbol(FieldSymbol symbol) { + return symbolResolver.getConAttributeSymbol(symbol); + } - return checker - .getIncarnationMapping() - .getIncarnations((ASTCDAttribute) symbol.getAstNode()) - .iterator() - .next() - .getSymbol(); + ISymbol getConMethodSymbol(ISymbol symbol) { + return symbolResolver.getConMethodSymbol(symbol); } } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/ConcreteSymbolResolver.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/ConcreteSymbolResolver.java new file mode 100644 index 00000000..b701173d --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/ConcreteSymbolResolver.java @@ -0,0 +1,432 @@ +package de.monticore.codeAdaption.handler; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._ast.ASTCDParameter; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdbasis._symboltable.CDTypeSymbol; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.MatcherHelper; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.symbols.oosymbols._symboltable.FieldSymbol; +import de.monticore.symboltable.ISymbol; +import de.se_rwth.commons.logging.Log; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** Resolves reference-CD symbols, signatures, and Java type names to concrete counterparts. */ +final class ConcreteSymbolResolver { + private final BasicUpdateHandler handler; + private final Map> concreteImportedTypes; + + ConcreteSymbolResolver( + BasicUpdateHandler handler, + ASTCDCompilationUnit referenceCD, + ASTCDCompilationUnit concreteCD) { + this.handler = handler; + this.concreteImportedTypes = importedTypes(concreteCD, referenceCD); + } + + String buildConcreteName(CodeMatching matching) { + List concreteReferences = new ArrayList<>(); + for (ISymbol reference : matching.getReferences()) { + Optional fromContext = handler.getSymbolFromContext(reference); + if (fromContext.isPresent()) { + concreteReferences.add(fromContext.get()); + } else if (reference instanceof CDTypeSymbol type) { + concreteReferences.add(handler.getConTypeSymbol(type)); + } else if (reference instanceof FieldSymbol field) { + concreteReferences.add(handler.getConAttributeSymbol(field)); + } else { + concreteReferences.add(handler.getConMethodSymbol(reference)); + } + } + String generationTemplate = matching.getGenerateTemplate(); + return MatcherHelper.fillTemplate( + generationTemplate != null && !generationTemplate.isEmpty() + ? generationTemplate + : matching.getTemplate(), + concreteReferences); + } + + Optional getSymbolFromContext(ISymbol reference) { + if (handler.incarnationContext == null) { + return Optional.empty(); + } + Optional selected = selectedIncarnation(reference); + if (selected.isPresent()) { + return selected.map(IncarnationContext.MappedElement::symbol); + } + List mappedIncarnations = + handler.mappedIncarnations(reference); + if (mappedIncarnations.isEmpty()) { + return Optional.empty(); + } + List incarnations = + mappedIncarnations.stream().map(IncarnationContext.MappedElement::symbol).toList(); + if (reference instanceof CDTypeSymbol && handler.useCommonParentForMultipleIncarnations) { + Optional commonParent = findCommonParent(incarnations); + if (commonParent.isPresent()) { + return commonParent; + } + for (ISymbol incarnation : incarnations) { + Optional grouping = groupingName(incarnation.getName()); + if (grouping.isPresent()) { + Optional groupingSymbol = findContextSymbolByName(grouping.get()); + if (groupingSymbol.isPresent()) { + return groupingSymbol; + } + } + } + } + return Optional.of(incarnations.get(0)); + } + + private Optional selectedIncarnation(ISymbol reference) { + Optional referenceKey = handler.referenceKey(reference); + if (referenceKey.isEmpty()) { + return Optional.empty(); + } + IncarnationContext.MappedElement direct = + handler.incarnationSelection.get(referenceKey.get()); + if (direct != null) { + return Optional.of(direct); + } + Optional referenceOwner = referenceKey.get().getOwnerType(); + if (referenceOwner.isEmpty()) { + return Optional.empty(); + } + IncarnationContext.MappedElement selectedOwner = + handler.incarnationSelection.get(StableElementKey.type(referenceOwner.get())); + if (selectedOwner == null) { + return Optional.empty(); + } + return handler.mappedIncarnations(reference).stream() + .filter( + incarnation -> + incarnation + .key() + .getOwnerType() + .filter(selectedOwner.key().getName()::equals) + .isPresent()) + .findFirst(); + } + + ISymbol getConTypeSymbol(CDTypeSymbol symbol) { + if (handler.checker == null || handler.checker.getIncarnationMapping() == null) { + Log.warn("No conformance incarnation mapping available for type " + symbol.getName()); + return symbol; + } + var incarnations = handler.checker.getIncarnationMapping().getIncarnations(symbol.getAstNode()); + if (incarnations != null && incarnations.iterator().hasNext()) { + return incarnations.iterator().next().getSymbol(); + } + for (ASTCDType referenceType : handler.refIndex.types()) { + if (referenceType.getName().equals(symbol.getName())) { + incarnations = handler.checker.getIncarnationMapping().getIncarnations(referenceType); + if (incarnations != null && incarnations.iterator().hasNext()) { + return incarnations.iterator().next().getSymbol(); + } + break; + } + } + Log.warn("No incarnation found for type " + symbol.getName() + "; using reference symbol"); + return symbol; + } + + ISymbol getConAttributeSymbol(FieldSymbol symbol) { + if (handler.checker == null || handler.checker.getIncarnationMapping() == null) { + Log.warn("No conformance incarnation mapping available for attribute " + symbol.getName()); + return symbol; + } + if (!(symbol.getAstNode() instanceof ASTCDAttribute attribute)) { + throw new IllegalStateException( + "Field symbol " + symbol.getName() + " has no ASTCDAttribute node"); + } + var incarnations = handler.checker.getIncarnationMapping().getIncarnations(attribute); + if (incarnations != null && incarnations.iterator().hasNext()) { + return incarnations.iterator().next().getSymbol(); + } + Log.warn("No incarnation found for attribute " + symbol.getName() + "; using reference symbol"); + return symbol; + } + + ISymbol getConMethodSymbol(ISymbol symbol) { + if (handler.checker != null + && handler.checker.getIncarnationMapping() != null + && symbol.getAstNode() instanceof ASTCDMethod method) { + var incarnations = handler.checker.getIncarnationMapping().getIncarnations(method); + if (incarnations != null && incarnations.iterator().hasNext()) { + return incarnations.iterator().next().getSymbol(); + } + } + Log.warn("No incarnation found for method " + symbol.getName() + "; using reference symbol"); + return symbol; + } + + Optional resolveConcreteMethodSymbol(CodeMatching matching) { + for (ISymbol reference : matching.getReferences()) { + if (!(reference.getAstNode() instanceof ASTCDMethod)) { + continue; + } + ISymbol concrete = + handler.getSymbolFromContext(reference).orElseGet(() -> handler.getConMethodSymbol(reference)); + if (concrete != reference && concrete.getAstNode() instanceof ASTCDMethod) { + return Optional.of(concrete); + } + } + return Optional.empty(); + } + + void registerConcreteMethodSignature(ISymbol reference, ISymbol concrete) { + if (concrete == null || !(concrete.getAstNode() instanceof ASTCDMethod concreteMethod)) { + return; + } + if (handler.incarnationContext != null) { + Optional referenceKey = handler.referenceKey(reference); + Optional concreteKey = handler.concreteKey(concrete); + if (referenceKey.isPresent() && concreteKey.isPresent()) { + List qualifiedParameterTypes = + concreteMethod.getCDParameterList().stream() + .map( + parameter -> + qualifyCdType(JavaSourceNames.printNormalizedType(parameter.getMCType()))) + .toList(); + StableElementKey qualifiedConcreteKey = + StableElementKey.method( + concreteKey.get().getOwnerType().orElse(null), + concreteKey.get().getName(), + qualifiedParameterTypes, + concreteKey.get().getReturnType().orElse(null)); + handler.updater.registerMethodRewrite(referenceKey.get(), qualifiedConcreteKey); + } + } + handler.updater.registerConcreteMethodSignature( + concreteMethod.getName(), + concreteMethod.getCDParameterList().stream() + .map(parameter -> qualifyCdType(JavaSourceNames.printNormalizedType(parameter.getMCType()))) + .toList()); + } + + Optional findConcreteMethod( + String concreteOwner, + String concreteMethodName, + List referenceParameters) { + List candidates = + handler.conIndex.methods(concreteOwner, concreteMethodName).stream() + .filter(method -> method.getCDParameterList().size() == referenceParameters.size()) + .toList(); + if (candidates.size() <= 1) { + return candidates.stream().findFirst(); + } + List expectedTypes = + referenceParameters.stream() + .map(parameter -> concreteType(JavaSourceNames.printNormalizedType(parameter.getMCType()))) + .toList(); + List exact = + candidates.stream() + .filter(method -> normalizedParameterTypes(method).equals(expectedTypes)) + .toList(); + if (exact.size() == 1) { + return Optional.of(exact.get(0)); + } + Log.warn( + "Ambiguous concrete overload " + + concreteOwner + + "." + + concreteMethodName + + "(" + + String.join(",", expectedTypes) + + ")"); + return Optional.empty(); + } + + String resolveConcreteTypeName(String referenceTypeName) { + Optional referenceType = handler.refIndex.type(JavaSourceNames.simpleName(referenceTypeName)); + if (referenceType.isPresent()) { + ISymbol resolved = + handler + .getSymbolFromContext(referenceType.get().getSymbol()) + .orElseGet(() -> handler.getConTypeSymbol(referenceType.get().getSymbol())); + if (resolved.getName().equals(referenceType.get().getName()) + && handler.incarnationContext != null) { + Optional concreteAlternative = + handler.mappedIncarnations(referenceType.get().getSymbol()).stream() + .map(element -> element.key().getName()) + .filter(name -> !name.equals(referenceType.get().getName())) + .filter(handler.conIndex::hasType) + .sorted() + .findFirst(); + if (concreteAlternative.isPresent()) { + return concreteAlternative.get(); + } + } + return resolved.getName(); + } + return handler.conIndex.type(JavaSourceNames.simpleName(referenceTypeName)).isPresent() + ? JavaSourceNames.simpleName(referenceTypeName) + : referenceTypeName; + } + + Optional findConcreteType(String typeName) { + return handler.conIndex.type(JavaSourceNames.simpleName(typeName)); + } + + String qualifyCdType(String type) { + return JavaSourceNames.replaceSimpleTypeNames( + type, + simpleName -> { + if (handler.conIndex.type(simpleName).isPresent() + || handler.refIndex.type(simpleName).isPresent()) { + return Optional.empty(); + } + Set candidates = concreteImportedTypes.get(simpleName); + if (candidates == null || candidates.isEmpty()) { + return Optional.empty(); + } + if (candidates.size() == 1) { + return Optional.of(candidates.iterator().next()); + } + throw new IllegalStateException( + "Ambiguous class-diagram imports for used type '" + + simpleName + + "': " + + candidates.stream().sorted().collect(java.util.stream.Collectors.joining(", "))); + }); + } + + String resolveConcreteCdType(String type) { + return qualifyCdType(concreteType(type)); + } + + String replaceConcreteWithGroupingType(String rawType) { + if (rawType == null + || rawType.isEmpty() + || handler.incarnationContext == null + || !handler.useCommonParentForMultipleIncarnations) { + return rawType; + } + return JavaSourceNames.replaceSimpleTypeNames( + rawType, + simple -> { + Optional direct = groupingName(simple); + if (direct.isPresent()) { + return direct; + } + for (Map.Entry> entry : + handler.incarnationContext.getMappings().entrySet()) { + if (entry.getKey().getName().equals(simple) && !entry.getValue().isEmpty()) { + return groupingName(entry.getValue().get(0).key().getName()); + } + } + return Optional.empty(); + }); + } + + private List normalizedParameterTypes(ASTCDMethod method) { + return method.getCDParameterList().stream() + .map(ASTCDParameter::getMCType) + .map(JavaSourceNames::printNormalizedType) + .toList(); + } + + private String concreteType(String type) { + return JavaSourceNames.replaceSimpleTypeNames( + type, + simple -> { + String concrete = resolveConcreteTypeName(simple); + return concrete.equals(simple) ? Optional.empty() : Optional.of(concrete); + }); + } + + private Optional findCommonParent(List incarnations) { + Set names = new HashSet<>(); + incarnations.forEach(symbol -> names.add(symbol.getName())); + for (String possibleGrouping : names) { + Optional groupingElement = + handler.incarnationContext.getGroupingMappings().values().stream() + .filter(element -> element.key().getName().equals(possibleGrouping)) + .findFirst(); + if (groupingElement.isEmpty()) { + continue; + } + Set implementers = + handler.incarnationContext.getGroupingMappings().entrySet().stream() + .filter(entry -> entry.getValue().key().getName().equals(possibleGrouping)) + .map(entry -> entry.getKey().getName()) + .filter(name -> !name.equals(possibleGrouping)) + .collect(java.util.stream.Collectors.toSet()); + Set remaining = new HashSet<>(names); + remaining.remove(possibleGrouping); + if (remaining.equals(implementers)) { + return Optional.of(groupingElement.get().symbol()); + } + } + return Optional.empty(); + } + + private Optional findContextSymbolByName(String name) { + Optional grouping = + handler.incarnationContext.getGroupingMappings().values().stream() + .filter(element -> element.key().getName().equals(name)) + .map(element -> element.symbol()) + .findFirst(); + if (grouping.isPresent()) { + return grouping; + } + for (Map.Entry> entry : + handler.incarnationContext.getMappings().entrySet()) { + Optional incarnation = + entry.getValue().stream() + .filter(element -> element.key().getName().equals(name)) + .map(element -> element.symbol()) + .findFirst(); + if (incarnation.isPresent()) { + return incarnation; + } + } + return Optional.empty(); + } + + private Optional groupingName(String concreteTypeName) { + return handler.incarnationContext + .getGroupingFor(StableElementKey.type(concreteTypeName)) + .map(grouping -> grouping.key().getName()); + } + + private static Map> importedTypes( + ASTCDCompilationUnit primary, ASTCDCompilationUnit fallback) { + Map> imports = importedTypes(fallback); + // Generated signatures describe concrete declarations, so concrete imports intentionally win + // over same-named reference imports. Ambiguities within the selected CD remain detectable. + importedTypes(primary).forEach(imports::put); + return imports; + } + + private static Map> importedTypes(ASTCDCompilationUnit cd) { + Map> imports = new LinkedHashMap<>(); + if (cd == null) { + return imports; + } + for (var statement : cd.getMCImportStatementList()) { + String imported = statement.getMCQualifiedName().getQName(); + if (!statement.isStar() && !imported.startsWith("java.lang.")) { + imports + .computeIfAbsent( + JavaSourceNames.simpleName(imported), ignored -> new LinkedHashSet<>()) + .add(imported); + } + } + return imports; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/JavaMemberUpdateService.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/JavaMemberUpdateService.java new file mode 100644 index 00000000..477822a1 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/JavaMemberUpdateService.java @@ -0,0 +1,440 @@ +package de.monticore.codeAdaption.handler; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._ast.ASTCDParameter; +import de.monticore.cdassociation._ast.ASTCDAssociation; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdbasis._symboltable.CDTypeSymbol; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.updater.CodeUpdater; +import de.monticore.codeAdaption.updater.CodeUpdater.MethodBodySpec; +import de.monticore.codeAdaption.utils.AdaptReference; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.codeAdaption.validator.CodeValidator; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.symbols.oosymbols._symboltable.FieldSymbol; +import de.monticore.symboltable.ISymbol; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.ArrayList; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * Translates member-level matchings into {@link CodeUpdater} operations. + * + *

The service handles local variables, parameters, fields, methods, supertypes, and Java member + * names derived from CD association roles. It resolves model mappings through {@link + * ConcreteSymbolResolver}; it does not orchestrate complete adaptation passes or mutate Spoon + * directly. + */ +final class JavaMemberUpdateService { + private final CodeValidator validator; + private final CodeUpdater updater; + private final CDModelIndex referenceIndex; + private final CDModelIndex concreteIndex; + private final ConcreteSymbolResolver symbols; + + /** Creates the member update phase from its matching, update, model, and symbol dependencies. */ + JavaMemberUpdateService( + CodeValidator validator, + CodeUpdater updater, + CDModelIndex referenceIndex, + CDModelIndex concreteIndex, + ConcreteSymbolResolver symbols) { + this.validator = validator; + this.updater = updater; + this.referenceIndex = referenceIndex; + this.concreteIndex = concreteIndex; + this.symbols = symbols; + } + + /** + * Renames matched local variables and parameters. Parameters that lack their own matching are + * subsequently aligned with the mapped concrete CD method by position. + */ + void handleVariableUpdate(JavaAstElemCollector collector) { + for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { + for (ASTMethodDeclaration method : collector.getAllMethodDeclarations(type)) { + for (ASTLocalVariableDeclaration variable : collector.getAllLocVariables(type, method)) { + Optional matching = + validator.getMatchedLocalVariable(type, method, variable); + if (matching.isPresent() && matching.get().mustBePerform()) { + updater.updateLocalVariable( + type, method, variable, symbols.buildConcreteName(matching.get())); + } + } + + Set updated = + Collections.newSetFromMap(new IdentityHashMap<>()); + for (ASTFormalParameter parameter : collector.getAllParameters(type, method)) { + Optional matching = + validator.getMatchedParameter(type, method, parameter); + if (matching.isPresent() && matching.get().mustBePerform()) { + updater.updateMethodParameter( + type, method, parameter, symbols.buildConcreteName(matching.get())); + updated.add(parameter); + } + } + updateMethodParametersFromConcreteCD(type, method, collector, updated); + } + } + } + + /** + * Copies still-unmodified parameter names from the mapped concrete CD method. An explicit + * parameter matching always wins and is therefore listed in {@code alreadyUpdated}. + */ + void updateMethodParametersFromConcreteCD( + ASTTypeDeclaration type, + ASTMethodDeclaration method, + JavaAstElemCollector collector, + Set alreadyUpdated) { + List referenceParameters = collector.getAllParameters(type, method); + if (referenceParameters.isEmpty() + || referenceParameters.stream().allMatch(alreadyUpdated::contains)) { + return; + } + Optional matching = validator.getMatchedMethod(type, method); + if (matching.isEmpty() || !matching.get().mustBePerform()) { + return; + } + + Optional concreteMethod = + symbols + .resolveConcreteMethodSymbol(matching.get()) + .filter(symbol -> symbol.getAstNode() instanceof ASTCDMethod) + .map(symbol -> (ASTCDMethod) symbol.getAstNode()); + if (concreteMethod.isEmpty()) { + String concreteOwner = symbols.resolveConcreteTypeName(type.getName()); + String concreteName = symbols.buildConcreteName(matching.get()); + concreteMethod = + symbols.findConcreteMethod(concreteOwner, concreteName, referenceParameters); + } + if (concreteMethod.isEmpty()) { + return; + } + + List concreteParameters = concreteMethod.get().getCDParameterList(); + for (int i = 0; i < referenceParameters.size() && i < concreteParameters.size(); i++) { + ASTFormalParameter referenceParameter = referenceParameters.get(i); + if (!alreadyUpdated.contains(referenceParameter)) { + updater.updateMethodParameter( + type, method, referenceParameter, concreteParameters.get(i).getName()); + } + } + } + + /** + * Updates methods, fields, and supertypes of ordinary mapped types. Types carrying a generation + * template are skipped because their member lifecycle is handled by generation. + */ + void handleMemberUpdate(JavaAstElemCollector collector) { + for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { + Optional typeMatching = validator.getMatchedType(type); + if (typeMatching.isPresent() + && typeMatching.get().getGenerateTemplate() != null + && !typeMatching.get().getGenerateTemplate().isEmpty()) { + continue; + } + updateMethods(type, collector); + updateFields(type, collector); + updateSupertypes(type, collector); + } + } + + /** + * Renames methods whose signature still fits the concrete declaration and replaces methods whose + * concrete parameter count differs. Methods used as {@code forEach} templates are not rewritten + * as ordinary one-to-one methods. + */ + private void updateMethods(ASTTypeDeclaration type, JavaAstElemCollector collector) { + for (ASTMethodDeclaration method : collector.getAllMethodDeclarations(type)) { + Optional matching = validator.getMatchedMethod(type, method); + if (matching.isEmpty() || !matching.get().mustBePerform()) { + continue; + } + if (matching.get().getReferences().stream().anyMatch(this::isForEachTargetMethod)) { + continue; + } + + boolean hasMethodReference = false; + Optional concreteMethod = Optional.empty(); + ISymbol referenceMethod = null; + for (ISymbol reference : matching.get().getReferences()) { + if (isMethodReference(reference)) { + hasMethodReference = true; + Optional resolved = resolveMappedMethod(reference); + if (resolved.isPresent()) { + referenceMethod = reference; + concreteMethod = resolved; + break; + } + } + } + + if (concreteMethod.isPresent()) { + symbols.registerConcreteMethodSignature(referenceMethod, concreteMethod.get()); + ASTCDMethod concreteDeclaration = (ASTCDMethod) concreteMethod.get().getAstNode(); + List sourceParameters = collector.getAllParameters(type, method); + if (sourceParameters.size() != concreteDeclaration.getCDParameterList().size()) { + updater.addMethod( + type, + method, + concreteDeclaration.getName(), + concreteDeclaration.getCDParameterList().stream() + .map( + parameter -> + symbols.resolveConcreteCdType( + JavaSourceNames.printNormalizedType(parameter.getMCType()))) + .toList(), + concreteDeclaration.getCDParameterList().stream() + .map(ASTCDParameter::getName) + .toList(), + symbols.resolveConcreteCdType( + JavaSourceNames.printNormalizedReturnType(concreteDeclaration)), + concreteDeclaration.getModifier().isStatic(), + concreteDeclaration.getCDParameterList().size() < sourceParameters.size() + ? MethodBodySpec.safeDefault() + : MethodBodySpec.empty()); + updater.removeMethod(type, method); + } else if (!concreteMethod.get().getName().equals(referenceMethod.getName())) { + updater.updateMethod(type, method, concreteMethod.get().getName()); + } + } else if (!hasMethodReference) { + updater.updateMethod(type, method, symbols.buildConcreteName(matching.get())); + } + } + } + + /** Resolves a reference method first from the incarnation context and then from conformance. */ + private Optional resolveMappedMethod(ISymbol reference) { + Optional fromContext = symbols.getSymbolFromContext(reference); + if (fromContext.isPresent() && fromContext.get().getAstNode() instanceof ASTCDMethod) { + return fromContext; + } + ISymbol fromChecker = symbols.getConMethodSymbol(reference); + if (fromChecker != reference && fromChecker.getAstNode() instanceof ASTCDMethod) { + return Optional.of(fromChecker); + } + return Optional.empty(); + } + + /** Distinguishes method-like symbols from CD type and field symbols in matcher references. */ + private boolean isMethodReference(ISymbol reference) { + return reference.getAstNode() instanceof ASTCDMethod + || (!(reference instanceof CDTypeSymbol) && !(reference instanceof FieldSymbol)); + } + + /** Renames every matched field of one Java type. */ + private void updateFields(ASTTypeDeclaration type, JavaAstElemCollector collector) { + for (ASTFieldDeclaration field : collector.getAllFieldDeclarations(type)) { + Optional matching = validator.getMatchedField(type, field); + if (matching.isPresent() && matching.get().mustBePerform()) { + updater.updateField(type, field, symbols.buildConcreteName(matching.get())); + } + } + } + + /** Rewrites every matched superclass or implemented interface of one Java type. */ + private void updateSupertypes(ASTTypeDeclaration type, JavaAstElemCollector collector) { + for (ASTMCType supertype : collector.getAllFSuperTypeDeclarations(type)) { + Optional matching = validator.getMatchedSupertype(type, supertype); + if (matching.isPresent() && matching.get().mustBePerform()) { + updater.updateSuperType(type, supertype, symbols.buildConcreteName(matching.get())); + } + } + } + + /** + * Rewrites Java names derived from CD association roles. For each adapted reference owner/target + * pair, the method finds the corresponding role in the concrete CD and rejects ambiguous role + * names instead of choosing one arbitrarily. + * + *

For example, if {@code Person -> Address} uses role {@code addresses} and the mapped {@code + * Customer -> Location} association uses {@code locations}, accesses to {@code + * Customer.addresses} are rewritten to {@code Customer.locations}. + */ + void handleAssociationRoleUpdate(JavaAstElemCollector collector) { + for (ASTTypeDeclaration javaType : collector.getAllTypeDeclarations()) { + Map rewrites = new LinkedHashMap<>(); + for (ASTCDAssociation referenceAssociation : referenceIndex.associations()) { + for (AssociationRole referenceRole : associationRoles(referenceAssociation)) { + if (!adaptsReferenceType(javaType, referenceRole.ownerType())) { + continue; + } + String concreteOwner = resolveConcreteAssociationType(referenceRole.ownerType()); + String concreteTarget = resolveConcreteAssociationType(referenceRole.targetType()); + Set concreteRoles = new LinkedHashSet<>(); + for (ASTCDAssociation concreteAssociation : concreteIndex.associations()) { + for (AssociationRole concreteRole : associationRoles(concreteAssociation)) { + if (concreteOwner.equals(concreteRole.ownerType()) + && concreteTarget.equals(concreteRole.targetType())) { + concreteRoles.add(concreteRole.roleName()); + } + } + } + addRoleRewrite(rewrites, referenceRole, concreteRoles); + } + } + rewrites.forEach( + (source, concrete) -> updater.updateAssociationRole(javaType, source, concrete)); + } + } + + /** Adds one unambiguous reference-role to concrete-role rewrite to the per-type rewrite map. */ + private void addRoleRewrite( + Map rewrites, AssociationRole referenceRole, Set concreteRoles) { + if (concreteRoles.size() > 1) { + if (concreteRoles.contains(referenceRole.roleName())) { + rewrites.putIfAbsent(referenceRole.roleName(), referenceRole.roleName()); + return; + } + throw new IllegalStateException( + "Ambiguous concrete association roles for " + + referenceRole.ownerType() + + "." + + referenceRole.roleName() + + ": " + + concreteRoles); + } + if (concreteRoles.size() == 1) { + String concreteRole = concreteRoles.iterator().next(); + String previous = rewrites.putIfAbsent(referenceRole.roleName(), concreteRole); + if (previous != null && !previous.equals(concreteRole)) { + throw new IllegalStateException( + "Conflicting concrete association roles for " + + referenceRole.ownerType() + + "." + + referenceRole.roleName()); + } + } + } + + /** + * Returns whether a referenced method is the target of another reference method's + * {@code <>} stereotype and must therefore be handled by expansion. + */ + boolean isForEachTargetMethod(ISymbol reference) { + if (!(reference.getAstNode() instanceof ASTCDMethod targetMethod)) { + return false; + } + Optional targetOwner = referenceIndex.ownerOf(targetMethod); + if (targetOwner.isEmpty()) { + return false; + } + for (ASTCDType referenceType : referenceIndex.types()) { + for (ASTCDMethod method : referenceType.getCDMethodList()) { + Optional target = stereotypeValue(method, "forEach"); + if (target.isPresent() + && referencesMethod(target.get(), referenceType, targetOwner.get(), targetMethod)) { + return true; + } + } + } + return false; + } + + /** Returns whether the Java declaration represents the supplied reference CD type. */ + private boolean adaptsReferenceType(ASTTypeDeclaration javaType, String referenceType) { + Optional matching = validator.getMatchedType(javaType); + return matching + .map( + value -> + value.getReferences().stream() + .filter(CDTypeSymbol.class::isInstance) + .map(ISymbol::getName) + .anyMatch(referenceType::equals)) + .orElse(false) + || referenceType.equals(javaType.getName()); + } + + /** Resolves a reference association endpoint to its selected concrete type name. */ + private String resolveConcreteAssociationType(String referenceType) { + Optional type = referenceIndex.type(referenceType); + if (type.isEmpty()) { + return referenceType; + } + ISymbol concrete = + symbols + .getSymbolFromContext(type.get().getSymbol()) + .orElseGet(() -> symbols.getConTypeSymbol(type.get().getSymbol())); + return JavaSourceNames.simpleName(concrete.getName()); + } + + /** + * Converts the present left and right CD roles into owner/target/name triples. A role belongs to + * the opposite endpoint because it names navigation from that owner toward the role's endpoint. + */ + private List associationRoles(ASTCDAssociation association) { + String left = JavaSourceNames.simpleName(association.getLeftQualifiedName().getQName()); + String right = JavaSourceNames.simpleName(association.getRightQualifiedName().getQName()); + List roles = new ArrayList<>(); + if (association.getLeft().isPresentCDRole()) { + roles.add(new AssociationRole(right, left, association.getLeft().getCDRole().getName())); + } + if (association.getRight().isPresentCDRole()) { + roles.add(new AssociationRole(left, right, association.getRight().getCDRole().getName())); + } + return roles; + } + + /** + * Matches a {@code forEach} target expressed as either a local method name or an owner-qualified + * method name. + */ + private boolean referencesMethod( + String referenceName, + ASTCDType annotatedOwner, + ASTCDType targetOwner, + ASTCDMethod method) { + Optional parsed = AdaptReference.parse(referenceName); + if (parsed.isEmpty()) { + return false; + } + AdaptReference reference = parsed.get(); + if (!method.getName().equals(reference.memberName())) { + return false; + } + if (reference.isMethod() + && !JavaSourceNames.methodSignature(method) + .equals(reference.methodSignature().orElseThrow())) { + return false; + } + if (reference.owner().isEmpty()) { + return annotatedOwner.getName().equals(targetOwner.getName()); + } + return targetOwner.getName().equals(JavaSourceNames.simpleName(reference.owner().get())); + } + + /** Reads one stereotype value and treats malformed generated AST values as absent. */ + private Optional stereotypeValue(ASTCDMethod method, String name) { + if (method.getModifier() == null || !method.getModifier().isPresentStereotype()) { + return Optional.empty(); + } + for (var stereotype : method.getModifier().getStereotype().getValuesList()) { + if (name.equals(stereotype.getName())) { + try { + return Optional.ofNullable(stereotype.getValue()); + } catch (RuntimeException ignored) { + return Optional.empty(); + } + } + } + return Optional.empty(); + } + + /** Directional association role: navigation owner, target type, and generated Java name. */ + private record AssociationRole(String ownerType, String targetType, String roleName) {} +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/JavaTypeUpdateService.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/JavaTypeUpdateService.java new file mode 100644 index 00000000..ef2fa336 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/JavaTypeUpdateService.java @@ -0,0 +1,669 @@ +package de.monticore.codeAdaption.handler; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._ast.ASTCDParameter; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDClass; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdbasis._symboltable.CDTypeSymbol; +import de.monticore.cdinterfaceandenum._ast.ASTCDEnum; +import de.monticore.cdinterfaceandenum._ast.ASTCDInterface; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.updater.CodeUpdater.MethodBodySpec; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.CDTypeRelations; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.symboltable.ISymbol; +import de.se_rwth.commons.logging.Log; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** Adapts and generates Java types and projects members introduced by CD completion. */ +final class JavaTypeUpdateService { + private final BasicUpdateHandler handler; + private final ConcreteSymbolResolver symbols; + private final JavaMemberUpdateService memberUpdates; + private final Set generatedTypes = new HashSet<>(); + + JavaTypeUpdateService( + BasicUpdateHandler handler, + ConcreteSymbolResolver symbols, + JavaMemberUpdateService memberUpdates) { + this.handler = handler; + this.symbols = symbols; + this.memberUpdates = memberUpdates; + } + + void beginRun() { + generatedTypes.clear(); + } + + void handleTypeUpdate(JavaAstElemCollector collector) { + for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { + Optional matching = handler.validator.getMatchedType(type); + if (matching.isEmpty() || !matching.get().mustBePerform()) { + continue; + } + if (matching.get().getGenerateTemplate() != null + && !matching.get().getGenerateTemplate().isEmpty()) { + generateTypeFromTemplate(type, matching.get(), collector); + } else { + handler.updater.updateType(type, handler.buildConcreteName(matching.get())); + } + } + + for (ASTCDType cdType : handler.refIndex.types()) { + String concreteName = symbols.resolveConcreteTypeName(cdType.getName()); + handler.updater.updateCDType(cdType, concreteName); + } + } + + private void generateTypeFromTemplate( + ASTTypeDeclaration templateType, + CodeMatching typeMatching, + JavaAstElemCollector collector) { + String generatedTypeName = handler.buildConcreteName(typeMatching); + if (!generatedTypes.add(generatedTypeName)) { + return; + } + handler.updater.addType(templateType, generatedTypeName); + + List templateFields = collector.getAllFieldDeclarations(templateType); + List templateMethods = collector.getAllMethodDeclarations(templateType); + if (templateFields.isEmpty() || templateMethods.isEmpty()) { + // A plain type template (for example Observer -> Attacker) is still a complete source + // template. Builder expansion needs both a field and a method prototype, but the absence of + // either prototype must not erase the declarations that the renamed type already owns. + return; + } + + String concreteName = resolveGeneratedTargetTypeName(templateType, typeMatching); + List attributes = collectGeneratedAttributes(concreteName); + ASTFieldDeclaration fieldTemplate = templateFields.get(0); + ASTMethodDeclaration methodTemplate = templateMethods.get(0); + List buildArguments = new ArrayList<>(); + for (GeneratedAttribute attribute : attributes) { + String fieldName = attribute.name() + "Field"; + handler.updater.addField(templateType, fieldTemplate, fieldName, attribute.type(), false); + buildArguments.add(fieldName); + handler.updater.addMethod( + templateType, + methodTemplate, + setterName(attribute.name()), + List.of(attribute.type()), + List.of(attribute.name()), + generatedTypeName, + false, + MethodBodySpec.assignFieldAndReturnThis(fieldName, attribute.name())); + } + handler.updater.addMethod( + templateType, + methodTemplate, + "build", + Collections.emptyList(), + Collections.emptyList(), + concreteName, + false, + MethodBodySpec.returnNew(concreteName, buildArguments)); + removeTemplateMembers(templateType, templateFields, templateMethods); + } + + private String resolveGeneratedTargetTypeName( + ASTTypeDeclaration templateType, CodeMatching matching) { + for (ISymbol reference : matching.getReferences()) { + if (reference instanceof CDTypeSymbol type) { + return handler + .getSymbolFromContext(reference) + .orElseGet(() -> handler.getConTypeSymbol(type)) + .getName(); + } + } + return symbols.resolveConcreteTypeName(templateType.getName()); + } + + private List collectGeneratedAttributes(String concreteName) { + Optional concreteType = symbols.findConcreteType(concreteName); + if (concreteType.isEmpty()) { + Log.warn("Cannot generate members: concrete type " + concreteName + " is not in the CD"); + return List.of(); + } + List attributes = new ArrayList<>(); + for (ASTCDAttribute attribute : concreteType.get().getCDAttributeList()) { + String type = JavaSourceNames.printNormalizedType(attribute.getMCType()); + if (handler.incarnationContext != null + && handler.useCommonParentForMultipleIncarnations) { + type = symbols.replaceConcreteWithGroupingType(type); + } + attributes.add( + new GeneratedAttribute(attribute.getName(), symbols.resolveConcreteCdType(type))); + } + return attributes; + } + + private void removeTemplateMembers( + ASTTypeDeclaration templateType, + List templateFields, + List templateMethods) { + for (ASTFieldDeclaration field : templateFields) { + try { + handler.updater.removeField(templateType, field); + } catch (RuntimeException exception) { + Log.debug( + "Could not remove template field: " + exception.getMessage(), + "JavaTypeUpdateService"); + } + } + for (ASTMethodDeclaration method : templateMethods) { + try { + handler.updater.removeMethod(templateType, method); + } catch (RuntimeException exception) { + Log.debug( + "Could not remove template method: " + exception.getMessage(), + "JavaTypeUpdateService"); + } + } + } + + void projectCompletedMembers(JavaAstElemCollector collector) { + for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { + Optional typeMatching = handler.validator.getMatchedType(type); + if (typeMatching.isEmpty() || !typeMatching.get().mustBePerform()) { + continue; + } + String concreteTypeName = handler.buildConcreteName(typeMatching.get()); + Optional concreteType = handler.conIndex.type(concreteTypeName); + if (concreteType.isEmpty()) { + continue; + } + projectFields(type, concreteType.get(), collector); + projectMethods(type, concreteType.get(), collector); + projectCompletionDelta(type, concreteType.get()); + } + } + + private void projectCompletionDelta(ASTTypeDeclaration javaType, ASTCDType completedType) { + Optional inputType = handler.inputConIndex.type(completedType.getName()); + + boolean completedAbstract = CDTypeRelations.isAbstract(completedType); + if (completedType instanceof ASTCDClass) { + // Reference templates may be abstract even when a concrete incarnation is not. Normalize + // every adapted class to the final target CD instead of treating abstractness only as a + // completion delta. + handler.updater.setTypeAbstract(javaType, completedAbstract); + } + + for (ASTCDAttribute completedField : completedType.getCDAttributeList()) { + Optional inputField = + inputType.flatMap( + type -> handler.inputConIndex.attribute(type.getName(), completedField.getName())); + String completedFieldType = JavaSourceNames.printNormalizedFieldType(completedField); + boolean unchanged = + inputField + .map(JavaSourceNames::printNormalizedFieldType) + .filter(completedFieldType::equals) + .isPresent(); + if (!unchanged) { + handler.updater.addField( + javaType, + null, + completedField.getName(), + symbols.resolveConcreteCdType(completedFieldType), + completedField.getModifier().isStatic()); + } + } + + for (ASTCDMethod completedMethod : completedType.getCDMethodList()) { + String signature = JavaSourceNames.methodSignature(completedMethod); + Optional inputMethod = + inputType.flatMap(type -> handler.inputConIndex.method(type.getName(), signature)); + String completedReturnType = JavaSourceNames.printNormalizedReturnType(completedMethod); + boolean unchanged = + inputMethod + .map(JavaSourceNames::printNormalizedReturnType) + .filter(completedReturnType::equals) + .isPresent(); + if (!unchanged) { + handler.updater.addMethod( + javaType, + null, + completedMethod.getName(), + completedMethod.getCDParameterList().stream() + .map(ASTCDParameter::getMCType) + .map(JavaSourceNames::printNormalizedType) + .map(symbols::resolveConcreteCdType) + .toList(), + completedMethod.getCDParameterList().stream().map(ASTCDParameter::getName).toList(), + symbols.resolveConcreteCdType(completedReturnType), + completedMethod.getModifier().isStatic(), + MethodBodySpec.empty()); + } + } + + String inputSuperclass = + inputType.flatMap(CDTypeRelations::firstSuperclassName) + .map(JavaSourceNames::simpleName) + .orElse(null); + String completedSuperclass = + CDTypeRelations.firstSuperclassName(completedType) + .map(JavaSourceNames::simpleName) + .orElse(null); + if (completedSuperclass != null && !completedSuperclass.equals(inputSuperclass)) { + handler.updater.addSuperType(javaType, completedSuperclass, false); + } + + Set inputInterfaces = + inputType.stream() + .flatMap(type -> CDTypeRelations.interfaceNames(type).stream()) + .map(JavaSourceNames::simpleName) + .collect(java.util.stream.Collectors.toSet()); + List addedInterfaces = CDTypeRelations.interfaceNames(completedType).stream() + .map(JavaSourceNames::simpleName) + .filter(interfaceName -> !inputInterfaces.contains(interfaceName)) + .distinct() + .toList(); + addedInterfaces.forEach( + interfaceName -> handler.updater.addSuperType(javaType, interfaceName, true)); + if (completedType instanceof ASTCDClass && !completedAbstract) { + Set completedEffectiveInterfaces = + effectiveInterfaceNames(handler.conIndex, completedType.getName()); + Set inputEffectiveInterfaces = + inputType + .map(type -> effectiveInterfaceNames(handler.inputConIndex, type.getName())) + .orElseGet(Set::of); + List introducedEffectiveInterfaces = + completedEffectiveInterfaces.stream() + .filter(interfaceName -> !inputEffectiveInterfaces.contains(interfaceName)) + .toList(); + projectInterfaceContracts(javaType, completedType, introducedEffectiveInterfaces); + } + + if (completedType instanceof ASTCDEnum completedEnum) { + Set inputConstants = + inputType + .filter(ASTCDEnum.class::isInstance) + .map(ASTCDEnum.class::cast) + .stream() + .flatMap(type -> type.getCDEnumConstantList().stream()) + .map(constant -> constant.getName()) + .collect(java.util.stream.Collectors.toSet()); + for (int index = 0; index < completedEnum.getCDEnumConstantList().size(); index++) { + String name = completedEnum.getCDEnumConstant(index).getName(); + if (!inputConstants.contains(name)) { + handler.updater.addEnumConstant(javaType, name, index); + } + } + } + } + + /** + * Returns every interface implemented directly or inherited through interfaces and + * superclasses. The visited set in the recursive helper makes malformed inheritance cycles safe. + */ + static Set effectiveInterfaceNames(CDModelIndex index, String typeName) { + Set result = new LinkedHashSet<>(); + collectEffectiveInterfaces(index, typeName, result, new LinkedHashSet<>()); + return result; + } + + private static void collectEffectiveInterfaces( + CDModelIndex index, + String typeName, + Set interfaces, + Set visitedTypes) { + String simpleName = JavaSourceNames.simpleName(typeName); + if (!visitedTypes.add(simpleName)) { + return; + } + ASTCDType type = index.type(simpleName).orElse(null); + if (type == null) { + return; + } + for (String interfaceName : CDTypeRelations.interfaceNames(type)) { + String simpleInterface = JavaSourceNames.simpleName(interfaceName); + interfaces.add(simpleInterface); + collectEffectiveInterfaces(index, simpleInterface, interfaces, visitedTypes); + } + CDTypeRelations.firstSuperclassName(type) + .ifPresent(parent -> collectEffectiveInterfaces(index, parent, interfaces, visitedTypes)); + } + + /** + * Materializes newly introduced interface contracts on a concrete Java class. Abstract classes + * intentionally skip this step; their concrete descendants receive any still-missing contracts. + */ + private void projectInterfaceContracts( + ASTTypeDeclaration javaType, ASTCDType completedType, List addedInterfaces) { + Map contracts = new LinkedHashMap<>(); + Set visitedInterfaces = new LinkedHashSet<>(); + for (String interfaceName : addedInterfaces) { + collectInterfaceContracts(interfaceName, contracts, visitedInterfaces); + } + + for (ASTCDMethod contract : contracts.values()) { + validateCompletedImplementation(completedType, contract); + handler.updater.addMethod( + javaType, + null, + contract.getName(), + contract.getCDParameterList().stream() + .map(ASTCDParameter::getMCType) + .map(JavaSourceNames::printNormalizedType) + .map(symbols::resolveConcreteCdType) + .toList(), + contract.getCDParameterList().stream().map(ASTCDParameter::getName).toList(), + symbols.resolveConcreteCdType(JavaSourceNames.printNormalizedReturnType(contract)), + false, + MethodBodySpec.interfaceContract()); + } + } + + /** + * Traverses parent interfaces first and keeps one method per normalized signature. Compatible + * covariant returns select the most specific declaration; incompatible returns fail explicitly. + */ + private void collectInterfaceContracts( + String interfaceName, + Map contracts, + Set visitedInterfaces) { + String simpleName = JavaSourceNames.simpleName(interfaceName); + if (!visitedInterfaces.add(simpleName)) { + return; + } + ASTCDType interfaceType = handler.conIndex.type(simpleName).orElse(null); + if (!(interfaceType instanceof ASTCDInterface)) { + throw new IllegalStateException( + "Completed Java interface '" + simpleName + "' is not an interface in the concrete CD"); + } + for (String parent : CDTypeRelations.interfaceNames(interfaceType)) { + collectInterfaceContracts(parent, contracts, visitedInterfaces); + } + for (ASTCDMethod method : interfaceType.getCDMethodList()) { + if (method.getModifier().isStatic()) { + continue; + } + String signature = JavaSourceNames.methodSignature(method); + ASTCDMethod existing = contracts.get(signature); + if (existing != null) { + String existingReturn = JavaSourceNames.printNormalizedReturnType(existing); + String candidateReturn = JavaSourceNames.printNormalizedReturnType(method); + if (!returnsAreCompatible(existingReturn, candidateReturn)) { + throw new IllegalStateException( + "Incompatible inherited interface contracts for " + + signature + + ": " + + existingReturn + + " and " + + candidateReturn); + } + if (isCovariantReturn(candidateReturn, existingReturn)) { + contracts.put(signature, method); + } + } else { + contracts.put(signature, method); + } + } + } + + private boolean returnsAreCompatible(String first, String second) { + return isCompatibleImplementationReturn(handler.conIndex, first, second) + || isCompatibleImplementationReturn(handler.conIndex, second, first); + } + + private boolean isCovariantReturn(String candidate, String parent) { + return !JavaSourceNames.normalizeType(candidate) + .equals(JavaSourceNames.normalizeType(parent)) + && isCompatibleImplementationReturn(handler.conIndex, candidate, parent); + } + + /** Tests Java-compatible equality or covariance for an implementation return type. */ + static boolean isCompatibleImplementationReturn( + CDModelIndex index, String actualReturn, String expectedReturn) { + String actual = JavaSourceNames.normalizeType(actualReturn); + String expected = JavaSourceNames.normalizeType(expectedReturn); + if (actual.equals(expected)) { + return true; + } + if ("Object".equals(JavaSourceNames.simpleName(expected)) && !isPrimitive(actual)) { + return true; + } + return index.isSubtypeOf(actual, expected); + } + + private static boolean isPrimitive(String type) { + return Set.of("boolean", "byte", "short", "int", "long", "char", "float", "double", "void") + .contains(type); + } + + /** Rejects a completed class method that already occupies a contract signature incompatibly. */ + private void validateCompletedImplementation(ASTCDType completedType, ASTCDMethod contract) { + String signature = JavaSourceNames.methodSignature(contract); + for (ASTCDMethod method : completedType.getCDMethodList()) { + if (!signature.equals(JavaSourceNames.methodSignature(method))) { + continue; + } + String expectedReturn = JavaSourceNames.printNormalizedReturnType(contract); + String actualReturn = JavaSourceNames.printNormalizedReturnType(method); + if (!isCompatibleImplementationReturn( + handler.conIndex, actualReturn, expectedReturn)) { + throw new IllegalStateException( + "Method " + + completedType.getName() + + "." + + signature + + " has return type " + + actualReturn + + " but interface contract requires " + + expectedReturn); + } + return; + } + } + + private void projectFields( + ASTTypeDeclaration type, ASTCDType concreteType, JavaAstElemCollector collector) { + for (ASTFieldDeclaration template : collector.getAllFieldDeclarations(type)) { + Optional matching = handler.validator.getMatchedField(type, template); + if (matching.isEmpty() || !matching.get().mustBePerform()) { + continue; + } + boolean generated = false; + boolean retainsTemplate = false; + for (ISymbol reference : matching.get().getReferences()) { + if (!(reference.getAstNode() instanceof ASTCDAttribute)) { + continue; + } + for (ASTCDAttribute concreteAttribute : concreteAttributesFor(reference)) { + if (isOwnedBy(concreteAttribute, concreteType)) { + generated = true; + if (isSelectedIncarnation(reference, concreteAttribute.getSymbol())) { + retainsTemplate = true; + continue; + } + retainsTemplate |= matches(template, concreteAttribute); + handler.updater.addField( + type, + template, + concreteAttribute.getName(), + symbols.resolveConcreteCdType( + JavaSourceNames.printNormalizedFieldType(concreteAttribute)), + concreteAttribute.getModifier().isStatic()); + } + } + } + if (generated && !retainsTemplate) { + handler.updater.removeField(type, template); + } + } + } + + private void projectMethods( + ASTTypeDeclaration type, ASTCDType concreteType, JavaAstElemCollector collector) { + for (ASTMethodDeclaration template : collector.getAllMethodDeclarations(type)) { + Optional matching = handler.validator.getMatchedMethod(type, template); + if (matching.isEmpty() || !matching.get().mustBePerform()) { + continue; + } + boolean generated = false; + boolean retainsTemplate = false; + for (ISymbol reference : matching.get().getReferences()) { + if (!(reference.getAstNode() instanceof ASTCDMethod) + || memberUpdates.isForEachTargetMethod(reference)) { + continue; + } + for (ASTCDMethod concreteMethod : concreteMethodsFor(reference)) { + if (isOwnedBy(concreteMethod, concreteType)) { + generated = true; + retainsTemplate |= matches(template, concreteMethod, type, collector); + handler.updater.addMethod( + type, + template, + concreteMethod.getName(), + concreteMethod.getCDParameterList().stream() + .map( + parameter -> + symbols.resolveConcreteCdType( + JavaSourceNames.printNormalizedType(parameter.getMCType()))) + .toList(), + concreteMethod.getCDParameterList().stream() + .map(ASTCDParameter::getName) + .toList(), + symbols.resolveConcreteCdType( + JavaSourceNames.printNormalizedReturnType(concreteMethod)), + concreteMethod.getModifier().isStatic(), + MethodBodySpec.empty()); + } + } + } + if (generated && !retainsTemplate) { + handler.updater.removeMethod(type, template); + } + } + } + + private boolean matches(ASTFieldDeclaration template, ASTCDAttribute concrete) { + String templateName = template.getVariableDeclarator(0).getDeclarator().getName(); + return templateName.equals(concrete.getName()) + && JavaSourceNames.printNormalizedType(template.getMCType()) + .equals(JavaSourceNames.printNormalizedFieldType(concrete)); + } + + private boolean matches( + ASTMethodDeclaration template, + ASTCDMethod concrete, + ASTTypeDeclaration owner, + JavaAstElemCollector collector) { + List templateParameters = + collector.getAllParameters(owner, template).stream() + .map(ASTFormalParameter::getMCType) + .map(JavaSourceNames::printNormalizedType) + .toList(); + List concreteParameters = + concrete.getCDParameterList().stream() + .map(ASTCDParameter::getMCType) + .map(JavaSourceNames::printNormalizedType) + .toList(); + return template.getName().equals(concrete.getName()) + && templateParameters.equals(concreteParameters) + && JavaSourceNames.normalizeType(JavaLoader.print(template.getMCReturnType())) + .equals(JavaSourceNames.printNormalizedReturnType(concrete)); + } + + private List concreteAttributesFor(ISymbol reference) { + List result = new ArrayList<>(); + if (reference.getAstNode() instanceof ASTCDAttribute attribute + && handler.checker != null + && handler.checker.getIncarnationMapping() != null) { + var incarnations = handler.checker.getIncarnationMapping().getIncarnations(attribute); + if (incarnations != null) { + for (var incarnation : incarnations) { + if (incarnation instanceof ASTCDAttribute concreteAttribute) { + result.add(concreteAttribute); + } + } + } + } + if (result.isEmpty() && handler.incarnationContext != null) { + for (var incarnation : handler.mappedIncarnations(reference)) { + if (incarnation.symbol().getAstNode() instanceof ASTCDAttribute concreteAttribute) { + result.add(concreteAttribute); + } + } + } + return result; + } + + private List concreteMethodsFor(ISymbol reference) { + List result = new ArrayList<>(); + if (reference.getAstNode() instanceof ASTCDMethod method + && handler.checker != null + && handler.checker.getIncarnationMapping() != null) { + var incarnations = handler.checker.getIncarnationMapping().getIncarnations(method); + if (incarnations != null) { + for (var incarnation : incarnations) { + if (incarnation instanceof ASTCDMethod concreteMethod) { + result.add(concreteMethod); + } + } + } + } + if (result.isEmpty() && handler.incarnationContext != null) { + for (var incarnation : handler.mappedIncarnations(reference)) { + if (incarnation.symbol().getAstNode() instanceof ASTCDMethod concreteMethod) { + result.add(concreteMethod); + } + } + } + return result; + } + + private boolean isOwnedBy(ASTCDAttribute attribute, ASTCDType owner) { + return handler.conIndex.ownerOf(attribute) + .map(candidate -> candidate == owner || candidate.getName().equals(owner.getName())) + .orElse(false); + } + + private boolean isOwnedBy(ASTCDMethod method, ASTCDType owner) { + return handler.conIndex.ownerOf(method) + .map(candidate -> candidate == owner || candidate.getName().equals(owner.getName())) + .orElse(false); + } + + private boolean isSelectedIncarnation(ISymbol reference, ISymbol concrete) { + Optional selected = handler.getSymbolFromContext(reference); + if (selected.isEmpty()) { + return false; + } + if (selected.get() == concrete || selected.get().getAstNode() == concrete.getAstNode()) { + return true; + } + if (handler.incarnationContext == null) { + return false; + } + Optional selectedKey = + handler.concreteKey(selected.get()); + Optional concreteKey = + handler.concreteKey(concrete); + return selectedKey.isPresent() && selectedKey.equals(concreteKey); + } + + private static String setterName(String attributeName) { + return attributeName == null || attributeName.isEmpty() + ? "set" + : "set" + JavaSourceNames.capitalize(attributeName); + } + + private record GeneratedAttribute(String name, String type) {} +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/AdaptationConflictDetector.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/AdaptationConflictDetector.java new file mode 100644 index 00000000..d53dcb11 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/AdaptationConflictDetector.java @@ -0,0 +1,57 @@ +package de.monticore.codeAdaption.handler.multiIncarnation; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.CodeAdaptationException; +import de.monticore.codeAdaption.handler.multiIncarnation.conflict.AdaptationConflictCheck; +import de.monticore.codeAdaption.handler.multiIncarnation.conflict.ConflictCollector; +import de.monticore.codeAdaption.handler.multiIncarnation.conflict.ConflictDetectionContext; +import de.monticore.codeAdaption.handler.multiIncarnation.conflict.DefaultConflictChecks; +import de.monticore.codeAdaption.utils.CDModelIndex; +import java.util.Map; +import java.util.Set; + +/** + * Runs manual adaptation conflict checks before Java output is cleaned or generated. + * + *

The detector is an orchestration facade over the built-in conflict-check strategies. + */ +public final class AdaptationConflictDetector { + + private AdaptationConflictDetector() {} + + /** + * Validates manual adaptation conflicts before Java output is cleaned or generated. + * + *

The detector covers type-kind mismatches, inheritance issues, duplicate or incompatible + * members, enum order mismatches, association ambiguities, underspecified {@code any} types, and + * unsupported forEach mappings. + */ + public static void validate( + CDModelIndex referenceIndex, + CDModelIndex concreteIndex, + Set mappings, + Map contexts, + Set confParams, + boolean useCommonParentForMultipleIncarnations) { + ConflictDetectionContext context = + new ConflictDetectionContext( + referenceIndex, + concreteIndex, + mappings, + contexts, + confParams, + useCommonParentForMultipleIncarnations); + ConflictCollector conflicts = new ConflictCollector(); + for (AdaptationConflictCheck check : DefaultConflictChecks.all()) { + check.check(context, conflicts); + } + + if (conflicts.hasConflicts()) { + throw new CodeAdaptationException( + "Manual code adaptation detected conflicts before output generation:" + + System.lineSeparator() + + "- " + + String.join(System.lineSeparator() + "- ", conflicts.formattedConflicts())); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationContext.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationContext.java new file mode 100644 index 00000000..96a08074 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationContext.java @@ -0,0 +1,107 @@ +package de.monticore.codeAdaption.handler.multiIncarnation; + +import de.monticore.symboltable.ISymbol; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * Immutable incarnation mappings for one adaptation mapping. Stable keys are the only lookup + * identity; MontiCore symbols are retained only as payload for AST operations. + */ +public class IncarnationContext { + /** + * Stable concrete identity plus the MontiCore symbol needed for AST operations. + * + * @param key stable key of the concrete CD element, for example the type key {@code CreditCard} + * @param symbol concrete MontiCore symbol whose AST node is used during adaptation + */ + public record MappedElement(StableElementKey key, ISymbol symbol) { + public MappedElement { + Objects.requireNonNull(key); + Objects.requireNonNull(symbol); + } + } + + private final String mappingName; + private final Map> mappings; + private final Map groupingByIncarnation; + + /** + * Creates an immutable context for one mapping. + * + *

Example: for mapping {@code "shop"}, {@code mappings} may associate reference type + * {@code Payment} with concrete types {@code CreditCard} and {@code Invoice}. If both concrete + * types must be used through {@code PaymentMethod}, {@code groupingByIncarnation} contains + * {@code CreditCard -> PaymentMethod} and {@code Invoice -> PaymentMethod}. + * + * @param mappingName name of the CD stereotype that identifies this mapping, such as {@code shop} + * @param mappings stable reference-element keys to one or more concrete incarnations; entries may + * represent types, fields, or signature-aware methods, for example {@code Payment -> + * [CreditCard, Invoice]} + * @param groupingByIncarnation concrete type-incarnation keys to the common concrete type through + * which shared Java declarations should reference their incarnation group; for example {@code + * CreditCard -> PaymentMethod}; may be {@code null} when no grouping is required + */ + public IncarnationContext( + String mappingName, + Map> mappings, + Map groupingByIncarnation) { + this.mappingName = Objects.requireNonNull(mappingName); + this.mappings = immutableMappings(mappings); + this.groupingByIncarnation = + Collections.unmodifiableMap( + new LinkedHashMap<>( + groupingByIncarnation == null ? Map.of() : groupingByIncarnation)); + } + + /** Returns the mapping stereotype name represented by this context. */ + public String getMappingName() { + return mappingName; + } + + /** + * Returns all immutable stable-key incarnation mappings, for example {@code Payment -> + * [CreditCard, Invoice]}. + */ + public Map> getMappings() { + return mappings; + } + + /** Returns the concrete incarnations of one stable reference key. */ + public List getIncarnations(StableElementKey referenceKey) { + return referenceKey == null ? List.of() : mappings.getOrDefault(referenceKey, List.of()); + } + + /** Returns the incarnation only when exactly one concrete target exists. */ + public Optional getUniqueIncarnation(StableElementKey referenceKey) { + List incarnations = getIncarnations(referenceKey); + return incarnations.size() == 1 ? Optional.of(incarnations.get(0)) : Optional.empty(); + } + + /** Returns the common grouping type selected for one concrete type incarnation. */ + public Optional getGroupingFor(StableElementKey incarnation) { + return Optional.ofNullable(groupingByIncarnation.get(incarnation)); + } + + /** + * Returns the complete immutable type-incarnation to grouping-type index, for example {@code + * CreditCard -> PaymentMethod} and {@code Invoice -> PaymentMethod}. + */ + public Map getGroupingMappings() { + return groupingByIncarnation; + } + + /** Copies both map and incarnation lists so callers cannot mutate context state after creation. */ + private static Map> immutableMappings( + Map> source) { + Map> copy = new LinkedHashMap<>(); + if (source != null) { + source.forEach((key, value) -> copy.put(key, value == null ? List.of() : List.copyOf(value))); + } + return Collections.unmodifiableMap(copy); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationContextBuilder.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationContextBuilder.java new file mode 100644 index 00000000..b1873854 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationContextBuilder.java @@ -0,0 +1,164 @@ +package de.monticore.codeAdaption.handler.multiIncarnation; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdconformance.CDConformanceChecker; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.se_rwth.commons.logging.Log; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** Builds incarnation contexts from checker results, optionally overlaid with stereotypes. */ +public class IncarnationContextBuilder { + private final CDConformanceChecker conformanceChecker; + private final IncarnationMappingSupport support; + + /** + * Creates a builder backed by one completed conformance check and indexes of the same model pair. + * + * @param conformanceChecker checker whose incarnation mapping supplies inferred relationships + * @param referenceIndex index of the reference CD + * @param concreteIndex index of the concrete CD checked against the reference CD + */ + public IncarnationContextBuilder( + CDConformanceChecker conformanceChecker, + CDModelIndex referenceIndex, + CDModelIndex concreteIndex) { + this.conformanceChecker = conformanceChecker; + this.support = new IncarnationMappingSupport(referenceIndex, concreteIndex); + } + + /** + * Builds a context from checker results and fills checker gaps from explicit mapping + * stereotypes. + * + * @param mapping stereotype name whose explicit mappings should be overlaid + * @return immutable context for the requested mapping + */ + public IncarnationContext buildContextForMapping(String mapping) { + return buildContextForMapping(mapping, true); + } + + /** + * Builds a context from inferred checker mappings and, when requested, explicit stereotypes. + * Explicit mappings are merged with rather than substituted for checker results; duplicate + * concrete targets are removed by {@link IncarnationMappingSupport}. + * + *

For example, if the checker maps {@code Payment -> CreditCard} and stereotype {@code + * <>} maps {@code Invoice}, enabling the overlay yields {@code Payment -> + * [CreditCard, Invoice]}; disabling it retains only {@code CreditCard}. + * + * @param mapping stereotype name represented by the resulting context + * @param overlayStereotypeMappings whether explicit stereotypes should fill or extend checker + * data + * @return immutable incarnation and grouping context + */ + public IncarnationContext buildContextForMapping( + String mapping, boolean overlayStereotypeMappings) { + Map> mappings = support.newMapping(); + if (conformanceChecker.getIncarnationMapping() != null) { + extractCheckerMappings(mappings); + } + if (overlayStereotypeMappings) { + Log.info( + "Overlaying stereotype context for mapping '" + mapping + "'", + "IncarnationContextBuilder"); + support.mergeMappings(mappings, extractStereotypeMappings(mapping)); + } + return support.assembleContext(mapping, mappings); + } + + /** + * Copies inferred type, field, and method incarnations from the checker into stable keys that + * remain usable after AST cloning. + */ + private void extractCheckerMappings( + Map> result) { + for (ASTCDType referenceType : support.referenceIndex().types()) { + var typeIncarnations = + conformanceChecker.getIncarnationMapping().getIncarnations(referenceType); + if (typeIncarnations != null) { + for (var incarnation : typeIncarnations) { + support.addMapping(result, StableElementKey.type(referenceType), incarnation.getSymbol()); + } + } + for (ASTCDAttribute referenceField : referenceType.getCDAttributeList()) { + var fieldIncarnations = + conformanceChecker.getIncarnationMapping().getIncarnations(referenceField); + if (fieldIncarnations == null) { + continue; + } + for (var incarnation : fieldIncarnations) { + support.addMapping( + result, StableElementKey.field(referenceType, referenceField), incarnation.getSymbol()); + } + } + for (ASTCDMethod referenceMethod : referenceType.getCDMethodList()) { + var methodIncarnations = + conformanceChecker.getIncarnationMapping().getIncarnations(referenceMethod); + if (methodIncarnations == null) { + continue; + } + for (var incarnation : methodIncarnations) { + support.addMapping( + result, StableElementKey.method(referenceType, referenceMethod), incarnation.getSymbol()); + } + } + } + } + + /** + * Extracts explicit mappings from stereotypes on concrete types and their members. Member + * references are resolved only within the reference owners mapped for the concrete type. + */ + private Map> extractStereotypeMappings( + String mapping) { + Map> result = support.newMapping(); + for (ASTCDType concreteType : support.concreteIndex().types()) { + Optional referenceTypeName = support.stereotypeValue(concreteType, mapping); + Optional referenceType = + referenceTypeName.flatMap(support::findReferenceType); + referenceType.ifPresent( + key -> support.addMapping(result, key, concreteType.getSymbol())); + + List referenceOwners = referenceOwners(concreteType, mapping, referenceTypeName); + for (ASTCDAttribute concreteField : concreteType.getCDAttributeList()) { + support + .stereotypeValue(concreteField, mapping) + .flatMap(name -> support.findReferenceField(referenceOwners, name)) + .ifPresent( + key -> support.addMapping(result, key, concreteField.getSymbol())); + } + for (ASTCDMethod concreteMethod : concreteType.getCDMethodList()) { + support + .stereotypeValue(concreteMethod, mapping) + .flatMap(name -> support.findReferenceMethod(referenceOwners, name)) + .ifPresent( + key -> support.addMapping(result, key, concreteMethod.getSymbol())); + } + } + return result; + } + + /** + * Finds the reference owners in which member stereotype names must be resolved, preferring the + * directly mapped reference type and then a mapped reference interface. + */ + private List referenceOwners( + ASTCDType concreteType, String mapping, Optional referenceTypeName) { + List owners = new ArrayList<>(); + referenceTypeName + .flatMap(support.referenceIndex()::type) + .ifPresent(owners::add); + if (owners.isEmpty()) { + support + .mappedInterfaceReference(concreteType, mapping) + .flatMap(support.referenceIndex()::type) + .ifPresent(owners::add); + } + return owners; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationMappingSupport.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationMappingSupport.java new file mode 100644 index 00000000..7973d057 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationMappingSupport.java @@ -0,0 +1,394 @@ +package de.monticore.codeAdaption.handler.multiIncarnation; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.utils.AdaptReference; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.symboltable.ISymbol; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +/** + * Shared reference indexing, stereotype interpretation, mapping merge, and grouping selection for + * the two incarnation-context construction modes. + */ +final class IncarnationMappingSupport { + private final CDModelIndex referenceIndex; + private final CDModelIndex concreteIndex; + private final ReferenceElementIndex referenceElements; + + IncarnationMappingSupport(CDModelIndex referenceIndex, CDModelIndex concreteIndex) { + this.referenceIndex = Objects.requireNonNull(referenceIndex, "referenceIndex"); + this.concreteIndex = Objects.requireNonNull(concreteIndex, "concreteIndex"); + this.referenceElements = new ReferenceElementIndex(referenceIndex); + } + + CDModelIndex referenceIndex() { + return referenceIndex; + } + + CDModelIndex concreteIndex() { + return concreteIndex; + } + + Map> newMapping() { + return new LinkedHashMap<>(); + } + + void addMapping( + Map> target, + StableElementKey reference, + ISymbol concrete) { + Optional concreteKey = StableElementKey.fromSymbol(concrete, concreteIndex); + if (reference == null || concreteKey.isEmpty()) { + return; + } + List incarnations = + target.computeIfAbsent(reference, ignored -> new ArrayList<>()); + boolean duplicate = + incarnations.stream().anyMatch(existing -> existing.key().equals(concreteKey.get())); + if (!duplicate) { + incarnations.add(new IncarnationContext.MappedElement(concreteKey.get(), concrete)); + } + } + + void mergeMappings( + Map> target, + Map> additions) { + for (Map.Entry> entry : additions.entrySet()) { + if (entry.getValue() == null) { + continue; + } + for (IncarnationContext.MappedElement incarnation : entry.getValue()) { + addMapping(target, entry.getKey(), incarnation.symbol()); + } + } + } + + IncarnationContext assembleContext( + String mapping, + Map> mappings) { + return new IncarnationContext(mapping, mappings, groupingTypes(mappings)); + } + + Optional stereotypeValue(ASTCDType type, String name) { + if (type == null || type.getModifier() == null || !type.getModifier().isPresentStereotype()) { + return Optional.empty(); + } + for (var value : type.getModifier().getStereotype().getValuesList()) { + if (name.equals(value.getName())) { + try { + return Optional.ofNullable(value.getValue()); + } catch (RuntimeException ignored) { + return Optional.empty(); + } + } + } + return Optional.empty(); + } + + Optional stereotypeValue(ASTCDAttribute attribute, String name) { + if (attribute == null + || attribute.getModifier() == null + || !attribute.getModifier().isPresentStereotype()) { + return Optional.empty(); + } + for (var value : attribute.getModifier().getStereotype().getValuesList()) { + if (name.equals(value.getName())) { + try { + return Optional.ofNullable(value.getValue()); + } catch (RuntimeException ignored) { + return Optional.empty(); + } + } + } + return Optional.empty(); + } + + Optional stereotypeValue(ASTCDMethod method, String name) { + if (method == null + || method.getModifier() == null + || !method.getModifier().isPresentStereotype()) { + return Optional.empty(); + } + for (var value : method.getModifier().getStereotype().getValuesList()) { + if (name.equals(value.getName())) { + try { + return Optional.ofNullable(value.getValue()); + } catch (RuntimeException ignored) { + return Optional.empty(); + } + } + } + return Optional.empty(); + } + + Optional findReferenceType(String name) { + return referenceElements.findType(name); + } + + Optional findReferenceField(List owners, String name) { + return referenceElements.findField(owners, name); + } + + Optional findReferenceMethod(List owners, String name) { + return referenceElements.findMethod(owners, name); + } + + Optional findSameNameField( + List owners, ASTCDAttribute concreteAttribute) { + List matches = new ArrayList<>(); + for (ASTCDType owner : owners) { + for (ASTCDAttribute candidate : owner.getCDAttributeList()) { + if (candidate.getName().equals(concreteAttribute.getName())) { + matches.add(StableElementKey.field(owner, candidate)); + } + } + } + return unique(matches); + } + + Optional findSameSignatureMethod( + List owners, ASTCDMethod concreteMethod) { + String signature = JavaSourceNames.methodSignature(concreteMethod); + List matches = new ArrayList<>(); + for (ASTCDType owner : owners) { + for (ASTCDMethod candidate : owner.getCDMethodList()) { + if (JavaSourceNames.methodSignature(candidate).equals(signature)) { + matches.add(StableElementKey.method(owner, candidate)); + } + } + } + return unique(matches); + } + + List mappedReferenceOwners( + Map> mappings, + ASTCDType concreteType) { + StableElementKey concreteKey = StableElementKey.type(concreteType); + List owners = new ArrayList<>(); + for (Map.Entry> entry : mappings.entrySet()) { + if (entry.getKey().getKind() != StableElementKey.Kind.TYPE) { + continue; + } + if (entry.getValue().stream() + .anyMatch(element -> element.key().equals(concreteKey))) { + referenceIndex.type(entry.getKey().getName()).ifPresent(owners::add); + } + } + return owners; + } + + Optional mappedInterfaceReference(ASTCDType concreteType, String mapping) { + for (String interfaceName : concreteIndex.directParentNames(concreteType.getName())) { + Optional possibleInterface = concreteIndex.type(interfaceName); + if (possibleInterface.isEmpty() || !isInterface(possibleInterface.get().getName())) { + continue; + } + Optional reference = stereotypeValue(possibleInterface.get(), mapping); + if (reference.isPresent() && findReferenceType(reference.get()).isPresent()) { + return reference; + } + } + return Optional.empty(); + } + + private Optional unique(List candidates) { + if (candidates.isEmpty()) { + return Optional.empty(); + } + T first = candidates.get(0); + for (int i = 1; i < candidates.size(); i++) { + if (!Objects.equals(candidates.get(i), first)) { + return Optional.empty(); + } + } + return Optional.of(first); + } + + /** + * Selects concrete interfaces that represent complete incarnation groups. + * + *

The returned map is keyed by each concrete incarnation and points to the common interface + * selected for its group. An interface is eligible only when its concrete class implementers + * exactly equal the incarnations in that group (the interface itself is ignored if it is also an + * incarnation). This exact-set rule prevents an unrelated implementer from becoming accepted by + * a rewritten field or parameter. + * + *

For example, {@code [CreditCard, Invoice]} may be grouped as {@code PaymentMethod} when + * those are exactly its concrete implementers, producing {@code CreditCard -> PaymentMethod} and + * {@code Invoice -> PaymentMethod}. If {@code Cash} also implements {@code PaymentMethod} but is + * not an incarnation of the same reference type, that interface is rejected. When several exact + * interfaces qualify, the nearest interface wins; its name breaks equal-distance ties + * deterministically. + */ + private Map groupingTypes( + Map> mappings) { + Map result = new LinkedHashMap<>(); + for (List incarnations : mappings.values()) { + Set targets = typeNames(incarnations); + if (targets.size() < 2) { + continue; + } + String best = null; + int bestDistance = Integer.MAX_VALUE; + for (ASTCDType iface : concreteIndex.interfaces()) { + Set expectedImplementers = new LinkedHashSet<>(targets); + expectedImplementers.remove(iface.getName()); + Set actualImplementers = new LinkedHashSet<>(); + for (ASTCDType type : concreteIndex.classes()) { + if (concreteIndex.isSubtypeOf(type.getName(), iface.getName())) { + actualImplementers.add(type.getName()); + } + } + if (!actualImplementers.equals(expectedImplementers)) { + continue; + } + int distance = maximumDistance(targets, iface.getName()); + if (distance < bestDistance + || (distance == bestDistance && (best == null || iface.getName().compareTo(best) < 0))) { + best = iface.getName(); + bestDistance = distance; + } + } + if (best != null) { + ASTCDType groupingType = concreteIndex.type(best).orElseThrow(); + IncarnationContext.MappedElement grouping = + new IncarnationContext.MappedElement( + StableElementKey.type(groupingType), groupingType.getSymbol()); + for (String target : targets) { + result.put(StableElementKey.type(target), grouping); + } + } + } + return result; + } + + private Set typeNames(List elements) { + Set result = new LinkedHashSet<>(); + if (elements == null) { + return result; + } + for (IncarnationContext.MappedElement element : elements) { + StableElementKey key = element.key(); + if (key != null && key.getKind() == StableElementKey.Kind.TYPE) { + result.add(key.getName()); + } + } + return result; + } + + private int maximumDistance(Set descendants, String ancestor) { + int maximum = 0; + for (String descendant : descendants) { + int distance = inheritanceDistance(descendant, ancestor); + if (distance == Integer.MAX_VALUE) { + return distance; + } + maximum = Math.max(maximum, distance); + } + return maximum; + } + + private int inheritanceDistance(String descendant, String ancestor) { + if (descendant.equals(ancestor)) { + return 0; + } + ArrayDeque queue = new ArrayDeque<>(); + Map distances = new LinkedHashMap<>(); + queue.add(descendant); + distances.put(descendant, 0); + while (!queue.isEmpty()) { + String current = queue.removeFirst(); + int nextDistance = distances.get(current) + 1; + for (String parent : concreteIndex.directParentNames(current)) { + if (parent.equals(ancestor)) { + return nextDistance; + } + if (!distances.containsKey(parent)) { + distances.put(parent, nextDistance); + queue.addLast(parent); + } + } + } + return Integer.MAX_VALUE; + } + + private boolean isInterface(String name) { + return concreteIndex.interfaces().stream().anyMatch(type -> type.getName().equals(name)); + } + + /** Owner- and signature-aware index. Ambiguous simple-name requests deliberately yield empty. */ + private static final class ReferenceElementIndex { + private final CDModelIndex index; + + private ReferenceElementIndex(CDModelIndex index) { + this.index = index; + } + + Optional findType(String requested) { + return index.type(requested).map(StableElementKey::type); + } + + Optional findField(List owners, String requested) { + Optional parsed = AdaptReference.parse(requested); + if (parsed.isEmpty() || parsed.get().isMethod()) { + return Optional.empty(); + } + AdaptReference reference = parsed.get(); + List matches = new ArrayList<>(); + String fieldName = reference.memberName(); + String explicitOwner = reference.owner().orElse(""); + for (ASTCDType owner : searchOwners(owners, explicitOwner)) { + index.attribute(owner.getName(), fieldName).ifPresent(matches::add); + } + if (matches.size() != 1) { + return Optional.empty(); + } + ASTCDAttribute match = matches.get(0); + return index.ownerOf(match).map(owner -> StableElementKey.field(owner, match)); + } + + Optional findMethod(List owners, String requested) { + Optional parsed = AdaptReference.parse(requested); + if (parsed.isEmpty()) { + return Optional.empty(); + } + AdaptReference reference = parsed.get(); + String explicitOwner = reference.owner().orElse(""); + List matches = new ArrayList<>(); + for (ASTCDType owner : searchOwners(owners, explicitOwner)) { + for (ASTCDMethod method : index.methods(owner.getName(), reference.memberName())) { + if (!reference.isMethod() + || JavaSourceNames.methodSignature(method) + .equals(reference.methodSignature().orElseThrow())) { + matches.add(method); + } + } + } + if (matches.size() != 1) { + return Optional.empty(); + } + ASTCDMethod match = matches.get(0); + return index.ownerOf(match).map(owner -> StableElementKey.method(owner, match)); + } + + private List searchOwners(List owners, String explicitOwner) { + if (!explicitOwner.isEmpty()) { + Optional owner = index.type(explicitOwner); + return owner.isPresent() ? List.of(owner.get()) : List.of(); + } + return owners == null || owners.isEmpty() ? index.types() : owners; + } + + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/ManualIncarnationContextBuilder.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/ManualIncarnationContextBuilder.java new file mode 100644 index 00000000..26171da7 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/ManualIncarnationContextBuilder.java @@ -0,0 +1,279 @@ +package de.monticore.codeAdaption.handler.multiIncarnation; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * Builds contexts from explicit stereotypes and deterministic name matches, without invoking + * cdconcretization or the conformance checker. + */ +public class ManualIncarnationContextBuilder { + private final Set confParams; + private final IncarnationMappingSupport support; + + /** + * Creates a manual builder for one reference/concrete model pair. + * + * @param referenceIndex index used to resolve referenced types and members + * @param concreteIndex index whose elements become concrete incarnations + * @param confParams mapping policies; {@link CDConfParameter#NAME_MAPPING} enables deterministic + * same-name fallback when no explicit stereotype is present + */ + public ManualIncarnationContextBuilder( + CDModelIndex referenceIndex, + CDModelIndex concreteIndex, + Set confParams) { + this.confParams = confParams; + this.support = new IncarnationMappingSupport(referenceIndex, concreteIndex); + } + + /** + * Builds one immutable mapping context without invoking conformance or concretization. + * Resolution order is explicit type/member stereotypes, optional same-name mapping, and finally + * expansion of reference-side {@code forEach} stereotypes. + * + * @param mapping stereotype name to read from concrete CD elements + * @return assembled incarnation and grouping context + */ + public IncarnationContext buildContextForMapping(String mapping) { + Map> mappings = support.newMapping(); + collectTypeMappings(mapping, mappings); + collectMemberMappings(mapping, mappings); + collectForEachMappings(mappings); + return support.assembleContext(mapping, mappings); + } + + /** Collects explicit or same-name mappings from reference type keys to concrete types. */ + private void collectTypeMappings( + String mapping, Map> mappings) { + for (ASTCDType concreteType : support.concreteIndex().types()) { + Optional explicit = support.stereotypeValue(concreteType, mapping); + if (explicit.isPresent()) { + support + .findReferenceType(explicit.get()) + .ifPresent(reference -> support.addMapping(mappings, reference, concreteType.getSymbol())); + } else if (confParams.contains(CDConfParameter.NAME_MAPPING)) { + support + .findReferenceType(concreteType.getName()) + .ifPresent(reference -> support.addMapping(mappings, reference, concreteType.getSymbol())); + } + } + } + + /** + * Collects field and method mappings inside the reference owners already selected for each + * concrete type. Explicit stereotypes take precedence over same-name/signature matching. + */ + private void collectMemberMappings( + String mapping, Map> mappings) { + for (ASTCDType concreteType : support.concreteIndex().types()) { + List referenceOwners = support.mappedReferenceOwners(mappings, concreteType); + for (ASTCDAttribute concreteField : concreteType.getCDAttributeList()) { + Optional explicit = support.stereotypeValue(concreteField, mapping); + if (explicit.isPresent()) { + support + .findReferenceField(referenceOwners, explicit.get()) + .ifPresent(reference -> support.addMapping(mappings, reference, concreteField.getSymbol())); + } else if (confParams.contains(CDConfParameter.NAME_MAPPING)) { + support + .findSameNameField(referenceOwners, concreteField) + .ifPresent(reference -> support.addMapping(mappings, reference, concreteField.getSymbol())); + } + } + for (ASTCDMethod concreteMethod : concreteType.getCDMethodList()) { + Optional explicit = support.stereotypeValue(concreteMethod, mapping); + if (explicit.isPresent()) { + support + .findReferenceMethod(referenceOwners, explicit.get()) + .ifPresent(reference -> support.addMapping(mappings, reference, concreteMethod.getSymbol())); + } else if (confParams.contains(CDConfParameter.NAME_MAPPING)) { + support + .findSameSignatureMethod(referenceOwners, concreteMethod) + .ifPresent(reference -> support.addMapping(mappings, reference, concreteMethod.getSymbol())); + } + } + } + } + + /** + * Expands manual {@code <>} mappings from already-known incarnations. A + * {@code forEach} reference may copy a type/member mapping directly or derive concrete accessor + * method names from a mapped field. + */ + private void collectForEachMappings( + Map> mappings) { + for (ASTCDType referenceType : support.referenceIndex().types()) { + support + .stereotypeValue(referenceType, "forEach") + .flatMap(support::findReferenceType) + .ifPresent( + target -> copyIncarnations(mappings, target, StableElementKey.type(referenceType))); + + for (ASTCDAttribute referenceField : referenceType.getCDAttributeList()) { + support.stereotypeValue(referenceField, "forEach").ifPresent( + name -> { + Optional target = + support.findReferenceField(List.of(referenceType), name); + if (target.isEmpty()) { + target = support.findReferenceMethod(List.of(referenceType), name); + } + target.ifPresent( + key -> copyIncarnations( + mappings, key, StableElementKey.field(referenceType, referenceField))); + }); + } + for (ASTCDMethod referenceMethod : referenceType.getCDMethodList()) { + Optional targetName = support.stereotypeValue(referenceMethod, "forEach"); + if (targetName.isEmpty()) { + continue; + } + Optional targetMethod = + support.findReferenceMethod(List.of(referenceType), targetName.get()); + if (targetMethod.isPresent()) { + copyIncarnations( + mappings, + targetMethod.get(), + StableElementKey.method(referenceType, referenceMethod)); + continue; + } + support + .findReferenceField(List.of(referenceType), targetName.get()) + .ifPresent( + target -> collectForEachMethods(mappings, target, referenceType, referenceMethod)); + } + } + } + + /** + * Finds concrete methods corresponding to a {@code forEach} method whose target is a mapped + * field, accepting the supported exact and camel-case name substitutions. + */ + private void collectForEachMethods( + Map> mappings, + StableElementKey targetField, + ASTCDType referenceOwner, + ASTCDMethod referenceMethod) { + List targetIncarnations = mappings.get(targetField); + if (targetIncarnations == null) { + return; + } + for (IncarnationContext.MappedElement incarnation : targetIncarnations) { + if (!(incarnation.symbol().getAstNode() instanceof ASTCDAttribute concreteField)) { + continue; + } + Optional owner = support.concreteIndex().ownerOf(concreteField); + if (owner.isEmpty()) { + continue; + } + Set names = + forEachMethodNames( + referenceMethod.getName(), targetField.getName(), concreteField.getName()); + for (ASTCDMethod concreteMethod : owner.get().getCDMethodList()) { + if (names.contains(concreteMethod.getName()) + && concreteMethod.getCDParameterList().size() + == referenceMethod.getCDParameterList().size()) { + support.addMapping( + mappings, + StableElementKey.method(referenceOwner, referenceMethod), + concreteMethod.getSymbol()); + } + } + } + } + + /** Copies all concrete incarnations of one stable reference key to another reference key. */ + private void copyIncarnations( + Map> mappings, + StableElementKey target, + StableElementKey reference) { + List incarnations = mappings.get(target); + if (incarnations == null) { + return; + } + for (IncarnationContext.MappedElement incarnation : incarnations) { + support.addMapping(mappings, reference, incarnation.symbol()); + } + } + + /** + * Produces candidate concrete method names by replacing a complete reference-name segment while + * preserving its capitalization form. + */ + private Set forEachMethodNames( + String methodName, String referenceTarget, String concreteTarget) { + Set result = new LinkedHashSet<>(); + if (methodName.equals(referenceTarget)) { + result.add(concreteTarget); + } + if (methodName.equals(JavaSourceNames.capitalize(referenceTarget))) { + result.add(JavaSourceNames.capitalize(concreteTarget)); + } + replaceNameSegment(methodName, referenceTarget, concreteTarget).ifPresent(result::add); + replaceNameSegment( + methodName, + JavaSourceNames.capitalize(referenceTarget), + JavaSourceNames.capitalize(concreteTarget)) + .ifPresent(result::add); + replaceNameSegment( + methodName, + JavaSourceNames.uncapitalize(referenceTarget), + JavaSourceNames.uncapitalize(concreteTarget)) + .ifPresent(result::add); + return result; + } + + /** + * Replaces only a complete camel-case name segment. For example, replacing {@code User} in + * {@code findUserById} yields {@code findCustomerById}, but replacing {@code Us} yields no match. + */ + private static Optional replaceNameSegment( + String name, String referenceSegment, String concreteSegment) { + if (name == null + || referenceSegment == null + || referenceSegment.isEmpty() + || concreteSegment == null + || concreteSegment.isEmpty()) { + return Optional.empty(); + } + List segments = splitNameSegments(name); + StringBuilder rewritten = new StringBuilder(name.length() + concreteSegment.length()); + boolean changed = false; + for (String segment : segments) { + if (segment.equals(referenceSegment)) { + rewritten.append(concreteSegment); + changed = true; + } else { + rewritten.append(segment); + } + } + return changed ? Optional.of(rewritten.toString()) : Optional.empty(); + } + + /** Splits a camel-case or acronym-containing Java identifier into capitalization segments. */ + private static List splitNameSegments(String name) { + List result = new ArrayList<>(); + int start = 0; + for (int i = 1; i < name.length(); i++) { + char previous = name.charAt(i - 1); + char current = name.charAt(i); + if (Character.isUpperCase(current) + && (Character.isLowerCase(previous) + || (i + 1 < name.length() && Character.isLowerCase(name.charAt(i + 1))))) { + result.add(name.substring(start, i)); + start = i; + } + } + result.add(name.substring(start)); + return result; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/StableElementKey.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/StableElementKey.java new file mode 100644 index 00000000..6c3122ee --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/StableElementKey.java @@ -0,0 +1,219 @@ +package de.monticore.codeAdaption.handler.multiIncarnation; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._ast.ASTCDParameter; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.symboltable.ISymbol; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * Stable identity for mapped CD elements. Symbols are still kept as metadata, but lookups should + * use these keys so independently loaded ASTs can resolve the same mapped element. + */ +public final class StableElementKey { + /** Supported CD element identity kinds. */ + public enum Kind { + /** CD class, interface, or enum identity. */ + TYPE, + /** Owner, name, and normalized type identity. */ + FIELD, + /** Owner, name, normalized parameters, and optional return type identity. */ + METHOD + } + + private final Kind kind; + private final String ownerType; + private final String name; + private final String fieldKind; + private final List parameterTypes; + private final List parameterTypeSources; + private final String returnType; + + private StableElementKey( + Kind kind, + String ownerType, + String name, + String fieldKind, + List parameterTypes, + String returnType) { + this.kind = Objects.requireNonNull(kind); + this.ownerType = normalize(ownerType); + this.name = normalize(name); + this.fieldKind = normalizeType(fieldKind); + this.parameterTypes = + parameterTypes == null + ? List.of() + : Collections.unmodifiableList(parameterTypes.stream().map(StableElementKey::normalizeType).toList()); + this.parameterTypeSources = + parameterTypes == null + ? List.of() + : Collections.unmodifiableList( + parameterTypes.stream().map(StableElementKey::normalizeTypeSource).toList()); + this.returnType = normalizeType(returnType); + } + + /** Creates a stable key for a CD type AST. */ + public static StableElementKey type(ASTCDType type) { + return type(type.getName()); + } + + /** Creates a stable key for a type name. */ + public static StableElementKey type(String typeName) { + return new StableElementKey(Kind.TYPE, null, typeName, null, List.of(), null); + } + + /** Creates an owner-aware stable key for a CD attribute AST. */ + public static StableElementKey field(ASTCDType owner, ASTCDAttribute attribute) { + return field(owner.getName(), attribute.getName(), JavaSourceNames.printNormalizedFieldType(attribute)); + } + + /** Creates an owner-aware field key from normalized identity components. */ + public static StableElementKey field(String ownerType, String fieldName, String fieldKind) { + return new StableElementKey(Kind.FIELD, ownerType, fieldName, fieldKind, List.of(), null); + } + + /** Creates an owner- and signature-aware stable key for a CD method AST. */ + public static StableElementKey method(ASTCDType owner, ASTCDMethod method) { + List parameters = new ArrayList<>(); + for (ASTCDParameter parameter : method.getCDParameterList()) { + parameters.add(JavaSourceNames.printNormalizedType(parameter.getMCType())); + } + String returnType = JavaSourceNames.printNormalizedReturnType(method); + return method(owner.getName(), method.getName(), parameters, returnType); + } + + /** Creates a method key without return-type identity. */ + public static StableElementKey method(String ownerType, String methodName, List parameterTypes) { + return method(ownerType, methodName, parameterTypes, null); + } + + /** Creates a method key with optional return-type identity. */ + public static StableElementKey method( + String ownerType, String methodName, List parameterTypes, String returnType) { + return new StableElementKey(Kind.METHOD, ownerType, methodName, null, parameterTypes, returnType); + } + + /** Builds a stable key for a symbol using the owning CD index for member ownership. */ + public static Optional fromSymbol(ISymbol symbol, CDModelIndex index) { + if (symbol == null || index == null) { + return Optional.empty(); + } + if (symbol.getAstNode() instanceof ASTCDType type) { + return Optional.of(type(type)); + } + if (symbol.getAstNode() instanceof ASTCDAttribute attribute) { + return index.ownerOf(attribute).map(owner -> field(owner, attribute)); + } + if (symbol.getAstNode() instanceof ASTCDMethod method) { + return index.ownerOf(method).map(owner -> method(owner, method)); + } + return Optional.empty(); + } + + public Kind getKind() { + return kind; + } + + public Optional getOwnerType() { + return Optional.ofNullable(ownerType); + } + + public String getName() { + return name; + } + + public Optional getFieldKind() { + return Optional.ofNullable(fieldKind); + } + + public List getParameterTypes() { + return parameterTypes; + } + + /** + * Returns the supplied parameter spellings with qualification intact. Stable-key equality still + * uses {@link #getParameterTypes() normalized simple-name identities}; consumers that create Java + * type references need these source spellings to distinguish types such as {@code alpha.Role} + * and {@code beta.Role}. + */ + public List getParameterTypeSources() { + return parameterTypeSources; + } + + public Optional getReturnType() { + return Optional.ofNullable(returnType); + } + + /** Returns whether both keys identify the same element without considering method return type. */ + public boolean sameSignatureIgnoringReturn(StableElementKey other) { + return other != null + && kind == other.kind + && Objects.equals(ownerType, other.ownerType) + && Objects.equals(name, other.name) + && Objects.equals(parameterTypes, other.parameterTypes); + } + + /** Returns the deterministic owner/name/type signature used in diagnostics and sorting. */ + public String signature() { + if (kind == Kind.TYPE) { + return name; + } + if (kind == Kind.FIELD) { + return ownerType + "." + name + ":" + fieldKind; + } + return ownerType + "." + name + "(" + String.join(",", parameterTypes) + ")"; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof StableElementKey other)) { + return false; + } + return kind == other.kind + && Objects.equals(ownerType, other.ownerType) + && Objects.equals(name, other.name) + && Objects.equals(fieldKind, other.fieldKind) + && Objects.equals(parameterTypes, other.parameterTypes) + && Objects.equals(returnType, other.returnType); + } + + @Override + public int hashCode() { + return Objects.hash(kind, ownerType, name, fieldKind, parameterTypes, returnType); + } + + @Override + public String toString() { + return signature() + (returnType == null ? "" : ":" + returnType); + } + + private static String normalize(String value) { + if (value == null || value.isBlank()) { + return null; + } + return value.trim(); + } + + private static String normalizeType(String value) { + String normalized = normalize(value); + if (normalized == null) { + return null; + } + return JavaSourceNames.normalizeType(normalized); + } + + private static String normalizeTypeSource(String value) { + String normalized = normalize(value); + return normalized == null ? "Object" : normalized; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/AdaptationConflictCheck.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/AdaptationConflictCheck.java new file mode 100644 index 00000000..811c0220 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/AdaptationConflictCheck.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +/** Interface for manual adaptation conflict checks. */ +public interface AdaptationConflictCheck { + + void check(ConflictDetectionContext context, ConflictCollector conflicts); +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/AmbiguousStereotypeConflictCheck.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/AmbiguousStereotypeConflictCheck.java new file mode 100644 index 00000000..13042425 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/AmbiguousStereotypeConflictCheck.java @@ -0,0 +1,46 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdconformance.CDConfParameter; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +final class AmbiguousStereotypeConflictCheck implements AdaptationConflictCheck { + + @Override + public void check(ConflictDetectionContext context, ConflictCollector conflicts) { + for (String mapping : context.mappings()) { + for (ASTCDType concreteType : context.concreteTypes().values()) { + Optional referenceTypeName = context.stereotypeValue(concreteType, mapping); + if (referenceTypeName.isEmpty() && context.confParams().contains(CDConfParameter.NAME_MAPPING)) { + referenceTypeName = Optional.of(concreteType.getName()); + } + ASTCDType referenceType = + context.referenceTypes().get(referenceTypeName.map(context::simpleName).orElse("")); + if (referenceType == null) { + continue; + } + Map methodsByName = new HashMap<>(); + for (ASTCDMethod method : referenceType.getCDMethodList()) { + methodsByName.merge(method.getName(), 1L, Long::sum); + } + for (ASTCDMethod concreteMethod : concreteType.getCDMethodList()) { + Optional stereotype = context.stereotypeValue(concreteMethod, mapping); + if (stereotype.isPresent() + && !stereotype.get().contains("(") + && methodsByName.getOrDefault(context.simpleName(stereotype.get()), 0L) > 1) { + conflicts.conflict( + mapping, + "ambiguous overloaded method stereotype", + concreteType.getName() + "." + concreteMethod.getName() + + " maps to overloaded reference method '" + + stereotype.get() + + "'"); + } + } + } + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/AssociationConflictCheck.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/AssociationConflictCheck.java new file mode 100644 index 00000000..9825dd58 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/AssociationConflictCheck.java @@ -0,0 +1,152 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import de.monticore.cdassociation._ast.ASTCDAssocSide; +import de.monticore.cdassociation._ast.ASTCDAssociation; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import java.util.Set; + +final class AssociationConflictCheck implements AdaptationConflictCheck { + + @Override + public void check(ConflictDetectionContext context, ConflictCollector conflicts) { + for (String mapping : context.mappings()) { + IncarnationContext incarnationContext = context.contexts().get(mapping); + if (incarnationContext == null) { + continue; + } + for (ASTCDAssociation referenceAssociation : context.referenceIndex().associations()) { + validateAssociation(context, conflicts, mapping, incarnationContext, referenceAssociation); + } + } + } + + private void validateAssociation( + ConflictDetectionContext context, + ConflictCollector conflicts, + String mapping, + IncarnationContext incarnationContext, + ASTCDAssociation referenceAssociation) { + String refLeft = context.simpleName(referenceAssociation.getLeftQualifiedName().getQName()); + String refRight = context.simpleName(referenceAssociation.getRightQualifiedName().getQName()); + Set leftTargets = context.concreteTypeNamesFor(incarnationContext, refLeft); + Set rightTargets = context.concreteTypeNamesFor(incarnationContext, refRight); + if (leftTargets.isEmpty() || rightTargets.isEmpty()) { + return; + } + for (ASTCDAssociation concreteAssociation : context.concreteIndex().associations()) { + String conLeft = context.simpleName(concreteAssociation.getLeftQualifiedName().getQName()); + String conRight = context.simpleName(concreteAssociation.getRightQualifiedName().getQName()); + boolean same = leftTargets.contains(conLeft) && rightTargets.contains(conRight); + boolean reverse = leftTargets.contains(conRight) && rightTargets.contains(conLeft); + if (same && reverse) { + conflicts.conflict( + mapping, + "ambiguous association direction", + context.associationName(concreteAssociation) + " can match " + + context.associationName(referenceAssociation) + + " in both directions"); + } else if (same) { + validateAssociationSides( + context, + conflicts, + mapping, + referenceAssociation.getLeft(), + concreteAssociation.getLeft(), + referenceAssociation.getRight(), + concreteAssociation.getRight(), + referenceAssociation, + concreteAssociation); + } else if (reverse) { + validateAssociationSides( + context, + conflicts, + mapping, + referenceAssociation.getLeft(), + concreteAssociation.getRight(), + referenceAssociation.getRight(), + concreteAssociation.getLeft(), + referenceAssociation, + concreteAssociation); + } + } + validateAssociationRoleConflicts( + context, conflicts, mapping, referenceAssociation, leftTargets, rightTargets); + } + + private void validateAssociationSides( + ConflictDetectionContext context, + ConflictCollector conflicts, + String mapping, + ASTCDAssocSide referenceLeft, + ASTCDAssocSide concreteLeft, + ASTCDAssocSide referenceRight, + ASTCDAssocSide concreteRight, + ASTCDAssociation referenceAssociation, + ASTCDAssociation concreteAssociation) { + validateCardinality( + context, conflicts, mapping, referenceLeft, concreteLeft, referenceAssociation, concreteAssociation); + validateCardinality( + context, conflicts, mapping, referenceRight, concreteRight, referenceAssociation, concreteAssociation); + } + + private void validateCardinality( + ConflictDetectionContext context, + ConflictCollector conflicts, + String mapping, + ASTCDAssocSide referenceSide, + ASTCDAssocSide concreteSide, + ASTCDAssociation referenceAssociation, + ASTCDAssociation concreteAssociation) { + if (referenceSide.isPresentCDCardinality() + && concreteSide.isPresentCDCardinality() + && !referenceSide.getCDCardinality().deepEquals(concreteSide.getCDCardinality())) { + conflicts.conflict( + mapping, + "association cardinality conflict", + context.associationName(concreteAssociation) + " has a cardinality incompatible with " + + context.associationName(referenceAssociation)); + } + } + + private void validateAssociationRoleConflicts( + ConflictDetectionContext context, + ConflictCollector conflicts, + String mapping, + ASTCDAssociation referenceAssociation, + Set leftTargets, + Set rightTargets) { + for (ConflictDetectionContext.RoleFieldCandidate referenceRole : + context.roleFieldCandidates(referenceAssociation)) { + Set ownerTargets = + referenceRole.owner().equals(context.simpleName(referenceAssociation.getLeftQualifiedName().getQName())) + ? leftTargets + : rightTargets; + Set targetTargets = + referenceRole.owner().equals(context.simpleName(referenceAssociation.getLeftQualifiedName().getQName())) + ? rightTargets + : leftTargets; + if (ownerTargets.isEmpty()) { + continue; + } + for (ASTCDAssociation other : context.concreteIndex().associations()) { + for (ConflictDetectionContext.RoleFieldCandidate concreteRole : + context.roleFieldCandidates(other)) { + if (!referenceRole.role().equals(concreteRole.role())) { + continue; + } + if (ownerTargets.contains(concreteRole.owner()) + && targetTargets.contains(concreteRole.target())) { + continue; + } + if (ownerTargets.contains(concreteRole.owner())) { + conflicts.conflict( + mapping, + "association role field conflict", + "role '" + referenceRole.role() + "' may create a duplicate Java field on " + + concreteRole.owner()); + } + } + } + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConcreteMemberConflictCheck.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConcreteMemberConflictCheck.java new file mode 100644 index 00000000..5b3d90c0 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConcreteMemberConflictCheck.java @@ -0,0 +1,78 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.utils.CDTypeRelations; +import java.util.ArrayDeque; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +final class ConcreteMemberConflictCheck implements AdaptationConflictCheck { + + @Override + public void check(ConflictDetectionContext context, ConflictCollector conflicts) { + for (ASTCDType type : context.concreteTypes().values()) { + Map fields = new LinkedHashMap<>(); + for (ASTCDAttribute field : type.getCDAttributeList()) { + String previous = fields.putIfAbsent(field.getName(), context.printType(field)); + if (previous != null && !previous.equals(context.printType(field))) { + conflicts.conflict( + "structure", + "duplicate field", + type.getName() + "." + field.getName() + " has incompatible types"); + } + } + validateInheritedFieldConflicts(context, conflicts, type, fields); + + Map methods = new LinkedHashMap<>(); + for (ASTCDMethod method : type.getCDMethodList()) { + String previous = methods.putIfAbsent(context.methodSignature(method), context.returnType(method)); + if (previous != null && !previous.equals(context.returnType(method))) { + conflicts.conflict( + "structure", + "duplicate method", + type.getName() + "." + context.methodSignature(method) + " has incompatible return types"); + } + } + } + } + + private void validateInheritedFieldConflicts( + ConflictDetectionContext context, + ConflictCollector conflicts, + ASTCDType type, + Map ownFields) { + ArrayDeque queue = new ArrayDeque<>(); + CDTypeRelations.firstSuperclassName(type).map(context::simpleName).ifPresent(queue::add); + for (String interfaceName : CDTypeRelations.interfaceNames(type)) { + queue.add(context.simpleName(interfaceName)); + } + Set visited = new HashSet<>(); + while (!queue.isEmpty()) { + ASTCDType parent = context.concreteTypes().get(queue.removeFirst()); + if (parent == null || !visited.add(parent.getName())) { + continue; + } + for (ASTCDAttribute inherited : parent.getCDAttributeList()) { + String ownType = ownFields.get(inherited.getName()); + if (ownType != null && !ownType.equals(context.printType(inherited))) { + conflicts.conflict( + "structure", + "inherited field conflict", + type.getName() + "." + inherited.getName() + + " conflicts with inherited " + + parent.getName() + + "." + + inherited.getName()); + } + } + CDTypeRelations.firstSuperclassName(parent).map(context::simpleName).ifPresent(queue::add); + for (String interfaceName : CDTypeRelations.interfaceNames(parent)) { + queue.add(context.simpleName(interfaceName)); + } + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConcreteTypeStructureConflictCheck.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConcreteTypeStructureConflictCheck.java new file mode 100644 index 00000000..1e3bdab2 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConcreteTypeStructureConflictCheck.java @@ -0,0 +1,99 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import de.monticore.cdbasis._ast.ASTCDClass; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdinterfaceandenum._ast.ASTCDInterface; +import de.monticore.codeAdaption.utils.CDTypeRelations; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +final class ConcreteTypeStructureConflictCheck implements AdaptationConflictCheck { + + @Override + public void check(ConflictDetectionContext context, ConflictCollector conflicts) { + for (ASTCDType type : context.concreteTypes().values()) { + if (type instanceof ASTCDClass cdClass && cdClass.getSuperclassList().size() > 1) { + conflicts.conflict( + "structure", + "illegal multiple class supertypes", + type.getName() + " extends more than one class"); + } + validateSuperTypeKinds(context, conflicts, type); + } + validateInheritanceCycles(context, conflicts); + } + + private void validateSuperTypeKinds( + ConflictDetectionContext context, ConflictCollector conflicts, ASTCDType type) { + if (type instanceof ASTCDClass) { + CDTypeRelations.firstSuperclassName(type) + .map(context::simpleName) + .map(context.concreteTypes()::get) + .filter(ASTCDInterface.class::isInstance) + .ifPresent( + superType -> + conflicts.conflict( + "structure", + "class extends interface", + type.getName() + " extends interface " + superType.getName())); + for (String interfaceName : CDTypeRelations.interfaceNames(type)) { + ASTCDType implemented = context.concreteTypes().get(context.simpleName(interfaceName)); + if (implemented != null && !(implemented instanceof ASTCDInterface)) { + conflicts.conflict( + "structure", + "class implements non-interface", + type.getName() + " implements " + implemented.getName()); + } + } + } else if (type instanceof ASTCDInterface) { + for (String interfaceName : CDTypeRelations.interfaceNames(type)) { + ASTCDType extended = context.concreteTypes().get(context.simpleName(interfaceName)); + if (extended != null && !(extended instanceof ASTCDInterface)) { + conflicts.conflict( + "structure", + "interface extends non-interface", + type.getName() + " extends " + extended.getName()); + } + } + } + } + + private void validateInheritanceCycles(ConflictDetectionContext context, ConflictCollector conflicts) { + Map> edges = new LinkedHashMap<>(); + for (ASTCDType type : context.concreteTypes().values()) { + Set parents = new LinkedHashSet<>(); + CDTypeRelations.firstSuperclassName(type).map(context::simpleName).ifPresent(parents::add); + for (String interfaceName : CDTypeRelations.interfaceNames(type)) { + parents.add(context.simpleName(interfaceName)); + } + parents.removeIf(parent -> !context.concreteTypes().containsKey(parent)); + edges.put(type.getName(), parents); + } + for (String typeName : edges.keySet()) { + if (hasCycle(typeName, edges, new LinkedHashSet<>(), new HashSet<>())) { + conflicts.conflict("structure", "inheritance cycle", "cycle reaches " + typeName); + } + } + } + + private boolean hasCycle( + String current, Map> edges, Set active, Set done) { + if (active.contains(current)) { + return true; + } + if (!done.add(current)) { + return false; + } + active.add(current); + for (String parent : edges.getOrDefault(current, Set.of())) { + if (hasCycle(parent, edges, active, done)) { + return true; + } + } + active.remove(current); + return false; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConflictCollector.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConflictCollector.java new file mode 100644 index 00000000..9534e2dc --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConflictCollector.java @@ -0,0 +1,32 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** Collect conflict messages. */ +public final class ConflictCollector { + + private final List conflicts = new ArrayList<>(); + + public void conflict(String mapping, String kind, String detail) { + conflicts.add( + "[" + + mapping + + "] " + + kind + + ": " + + detail + + ". Run with useConcretization=true or make the manual mapping explicit."); + } + + public boolean hasConflicts() { + return !conflicts.isEmpty(); + } + + public List formattedConflicts() { + List formatted = new ArrayList<>(conflicts); + Collections.sort(formatted); + return formatted; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConflictDetectionContext.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConflictDetectionContext.java new file mode 100644 index 00000000..38b252a7 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ConflictDetectionContext.java @@ -0,0 +1,231 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdassociation._ast.ASTCDAssociation; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDClass; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.cdinterfaceandenum._ast.ASTCDEnum; +import de.monticore.cdinterfaceandenum._ast.ASTCDInterface; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.CDTypeRelations; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** Shared helper API for adaptation conflict checks. */ +public final class ConflictDetectionContext { + + private final Set mappings; + private final Map contexts; + private final Set confParams; + private final boolean useCommonParentForMultipleIncarnations; + private final CDModelIndex referenceIndex; + private final CDModelIndex concreteIndex; + private final Map referenceTypes = new LinkedHashMap<>(); + private final Map concreteTypes = new LinkedHashMap<>(); + + public ConflictDetectionContext( + CDModelIndex referenceIndex, + CDModelIndex concreteIndex, + Set mappings, + Map contexts, + Set confParams, + boolean useCommonParentForMultipleIncarnations) { + this.mappings = mappings; + this.contexts = contexts; + this.confParams = confParams; + this.useCommonParentForMultipleIncarnations = useCommonParentForMultipleIncarnations; + this.referenceIndex = referenceIndex; + this.concreteIndex = concreteIndex; + referenceIndex.types().forEach(type -> referenceTypes.put(type.getName(), type)); + concreteIndex.types().forEach(type -> concreteTypes.put(type.getName(), type)); + } + + public Set mappings() { + return mappings; + } + + public Map contexts() { + return contexts; + } + + public Set confParams() { + return confParams; + } + + public boolean useCommonParentForMultipleIncarnations() { + return useCommonParentForMultipleIncarnations; + } + + public CDModelIndex referenceIndex() { + return referenceIndex; + } + + public CDModelIndex concreteIndex() { + return concreteIndex; + } + + public Map referenceTypes() { + return referenceTypes; + } + + public Map concreteTypes() { + return concreteTypes; + } + + public Set concreteTypeNamesFor(IncarnationContext context, String referenceTypeName) { + Set result = new LinkedHashSet<>(); + for (var incarnation : context.getIncarnations(StableElementKey.type(referenceTypeName))) { + result.add(incarnation.key().getName()); + } + if (result.isEmpty() && concreteTypes.containsKey(referenceTypeName)) { + result.add(referenceTypeName); + } + return result; + } + + public Set concreteParentNames(ASTCDType concrete) { + Set parents = new LinkedHashSet<>(); + CDTypeRelations.firstSuperclassName(concrete).map(this::simpleName).ifPresent(parents::add); + for (String interfaceName : CDTypeRelations.interfaceNames(concrete)) { + parents.add(simpleName(interfaceName)); + } + parents.removeIf(parent -> !concreteIndex.hasType(parent)); + return parents; + } + + public Optional stereotypeValue(ASTCDType cdType, String mapping) { + if (cdType.getModifier() == null || !cdType.getModifier().isPresentStereotype()) { + return Optional.empty(); + } + for (var stereotype : cdType.getModifier().getStereotype().getValuesList()) { + if (mapping.equals(stereotype.getName())) { + try { + return Optional.ofNullable(stereotype.getValue()); + } catch (Exception ignored) { + return Optional.empty(); + } + } + } + return Optional.empty(); + } + + public Optional stereotypeValue(ASTCDMethod cdMethod, String mapping) { + if (cdMethod.getModifier() == null || !cdMethod.getModifier().isPresentStereotype()) { + return Optional.empty(); + } + for (var stereotype : cdMethod.getModifier().getStereotype().getValuesList()) { + if (mapping.equals(stereotype.getName())) { + try { + return Optional.ofNullable(stereotype.getValue()); + } catch (Exception ignored) { + return Optional.empty(); + } + } + } + return Optional.empty(); + } + + public Optional stereotypeValue(ASTCDAttribute cdAttribute, String mapping) { + if (cdAttribute.getModifier() == null || !cdAttribute.getModifier().isPresentStereotype()) { + return Optional.empty(); + } + for (var stereotype : cdAttribute.getModifier().getStereotype().getValuesList()) { + if (mapping.equals(stereotype.getName())) { + try { + return Optional.ofNullable(stereotype.getValue()); + } catch (Exception ignored) { + return Optional.empty(); + } + } + } + return Optional.empty(); + } + + public Optional forEachValue(Object element) { + if (element instanceof ASTCDType type) { + return stereotypeValue(type, "forEach"); + } + if (element instanceof ASTCDAttribute attribute) { + return stereotypeValue(attribute, "forEach"); + } + if (element instanceof ASTCDMethod method) { + return stereotypeValue(method, "forEach"); + } + return Optional.empty(); + } + + public String typeKind(ASTCDType type) { + if (type instanceof ASTCDClass) { + return "class"; + } + if (type instanceof ASTCDInterface) { + return "interface"; + } + if (type instanceof ASTCDEnum) { + return "enum"; + } + return type.getClass().getSimpleName(); + } + + public String printType(ASTCDAttribute attribute) { + return JavaSourceNames.printNormalizedFieldType(attribute); + } + + public String methodSignature(ASTCDMethod method) { + return JavaSourceNames.methodSignature(method); + } + + public String returnType(ASTCDMethod method) { + return JavaSourceNames.printNormalizedReturnType(method); + } + + public boolean isAny(String type) { + return "any".equals(type == null ? "" : type.trim()); + } + + public String printedType(Object astType) { + if (astType instanceof de.monticore.types.mcbasictypes._ast.ASTMCType type) { + return JavaLoader.print(type); + } + return astType == null ? "" : astType.toString(); + } + + public String associationName(ASTCDAssociation association) { + if (association.isPresentName()) { + return association.getName(); + } + return association.getLeftQualifiedName().getQName() + + "--" + + association.getRightQualifiedName().getQName(); + } + + public String simpleName(String name) { + return JavaSourceNames.simpleName(name); + } + + public List roleFieldCandidates(ASTCDAssociation association) { + List result = new ArrayList<>(); + String left = simpleName(association.getLeftQualifiedName().getQName()); + String right = simpleName(association.getRightQualifiedName().getQName()); + if (association.getLeft().isPresentCDRole()) { + result.add(new RoleFieldCandidate(right, association.getLeft().getCDRole().getName(), left)); + } + if (association.getRight().isPresentCDRole()) { + result.add(new RoleFieldCandidate(left, association.getRight().getCDRole().getName(), right)); + } + return result; + } + + public record RoleFieldCandidate(String owner, String role, String target) {} +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/DefaultConflictChecks.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/DefaultConflictChecks.java new file mode 100644 index 00000000..2aa549c7 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/DefaultConflictChecks.java @@ -0,0 +1,21 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import java.util.List; + +/** Registry for the conflict checks. */ +public final class DefaultConflictChecks { + + private DefaultConflictChecks() {} + + public static List all() { + return List.of( + new ManualMappingConflictCheck(), + new ConcreteTypeStructureConflictCheck(), + new ConcreteMemberConflictCheck(), + new EnumConflictCheck(), + new AssociationConflictCheck(), + new UnderspecifiedTypeConflictCheck(), + new AmbiguousStereotypeConflictCheck(), + new ForEachConflictCheck()); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/EnumConflictCheck.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/EnumConflictCheck.java new file mode 100644 index 00000000..63c4eef1 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/EnumConflictCheck.java @@ -0,0 +1,62 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdinterfaceandenum._ast.ASTCDEnum; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +final class EnumConflictCheck implements AdaptationConflictCheck { + + @Override + public void check(ConflictDetectionContext context, ConflictCollector conflicts) { + for (IncarnationContext incarnationContext : context.contexts().values()) { + for (Map.Entry> entry : + incarnationContext.getMappings().entrySet()) { + if (entry.getKey().getKind() != StableElementKey.Kind.TYPE) { + continue; + } + ASTCDType reference = context.referenceTypes().get(entry.getKey().getName()); + if (!(reference instanceof ASTCDEnum referenceEnum)) { + continue; + } + for (IncarnationContext.MappedElement target : entry.getValue()) { + ASTCDType concrete = context.concreteTypes().get(target.key().getName()); + if (concrete instanceof ASTCDEnum concreteEnum) { + validateEnumOrder(context, conflicts, incarnationContext.getMappingName(), referenceEnum, concreteEnum); + } + } + } + } + } + + private void validateEnumOrder( + ConflictDetectionContext context, + ConflictCollector conflicts, + String mapping, + ASTCDEnum referenceEnum, + ASTCDEnum concreteEnum) { + Map concretePositions = new HashMap<>(); + for (int i = 0; i < concreteEnum.getCDEnumConstantList().size(); i++) { + concretePositions.put(concreteEnum.getCDEnumConstant(i).getName(), i); + } + int lastSeen = -1; + for (var referenceConstant : referenceEnum.getCDEnumConstantList()) { + Integer concretePosition = concretePositions.get(referenceConstant.getName()); + if (concretePosition == null) { + continue; + } + if (concretePosition < lastSeen) { + conflicts.conflict( + mapping, + "enum order conflict", + concreteEnum.getName() + " orders reference constants differently from " + + referenceEnum.getName()); + return; + } + lastSeen = concretePosition; + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ForEachConflictCheck.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ForEachConflictCheck.java new file mode 100644 index 00000000..5c9a6483 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ForEachConflictCheck.java @@ -0,0 +1,63 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import java.util.Optional; + +final class ForEachConflictCheck implements AdaptationConflictCheck { + + @Override + public void check(ConflictDetectionContext context, ConflictCollector conflicts) { + for (String mapping : context.mappings()) { + IncarnationContext incarnationContext = context.contexts().get(mapping); + if (incarnationContext == null) { + continue; + } + for (ASTCDType referenceType : context.referenceTypes().values()) { + validateForEachMapping( + context, conflicts, mapping, incarnationContext, StableElementKey.type(referenceType), referenceType); + for (ASTCDAttribute attribute : referenceType.getCDAttributeList()) { + validateForEachMapping( + context, + conflicts, + mapping, + incarnationContext, + StableElementKey.field(referenceType, attribute), + attribute); + } + for (ASTCDMethod method : referenceType.getCDMethodList()) { + validateForEachMapping( + context, + conflicts, + mapping, + incarnationContext, + StableElementKey.method(referenceType, method), + method); + } + } + } + } + + private void validateForEachMapping( + ConflictDetectionContext context, + ConflictCollector conflicts, + String mapping, + IncarnationContext incarnationContext, + StableElementKey key, + Object element) { + Optional forEachValue = context.forEachValue(element); + if (forEachValue.isEmpty()) { + return; + } + if (incarnationContext.getIncarnations(key).isEmpty()) { + conflicts.conflict( + mapping, + "missing forEach incarnation", + key.signature() + " declares forEach='" + forEachValue.get() + + "' but no concrete incarnation could be derived"); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ManualMappingConflictCheck.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ManualMappingConflictCheck.java new file mode 100644 index 00000000..2dc75b1a --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/ManualMappingConflictCheck.java @@ -0,0 +1,140 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import de.monticore.cdbasis._ast.ASTCDClass; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdinterfaceandenum._ast.ASTCDInterface; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +final class ManualMappingConflictCheck implements AdaptationConflictCheck { + + @Override + public void check(ConflictDetectionContext context, ConflictCollector conflicts) { + for (IncarnationContext incarnationContext : context.contexts().values()) { + for (Map.Entry> entry : + incarnationContext.getMappings().entrySet()) { + StableElementKey reference = entry.getKey(); + for (IncarnationContext.MappedElement mapped : entry.getValue()) { + StableElementKey concrete = mapped.key(); + if (reference.getKind() == StableElementKey.Kind.TYPE) { + validateTypeMapping(context, conflicts, incarnationContext, reference, concrete); + } + } + if (reference.getKind() == StableElementKey.Kind.FIELD && entry.getValue().size() > 1) { + validateFieldTargets( + conflicts, + incarnationContext.getMappingName(), + reference, + entry.getValue().stream().map(IncarnationContext.MappedElement::key).toList()); + } + if (reference.getKind() == StableElementKey.Kind.METHOD && entry.getValue().size() > 1) { + validateMethodTargets( + conflicts, + incarnationContext.getMappingName(), + reference, + entry.getValue().stream().map(IncarnationContext.MappedElement::key).toList()); + } + } + } + } + + private void validateTypeMapping( + ConflictDetectionContext context, + ConflictCollector conflicts, + IncarnationContext incarnationContext, + StableElementKey referenceKey, + StableElementKey concreteKey) { + ASTCDType reference = context.referenceTypes().get(referenceKey.getName()); + ASTCDType concrete = context.concreteTypes().get(concreteKey.getName()); + if (reference == null || concrete == null) { + return; + } + if (!context.typeKind(reference).equals(context.typeKind(concrete))) { + if (canUseCommonParentForTypeMismatch(context, incarnationContext, referenceKey, reference, concrete)) { + return; + } + conflicts.conflict( + incarnationContext.getMappingName(), + "type-kind mismatch", + reference.getName() + " is a " + context.typeKind(reference) + " but " + + concrete.getName() + " is a " + context.typeKind(concrete)); + } + } + + private boolean canUseCommonParentForTypeMismatch( + ConflictDetectionContext context, + IncarnationContext incarnationContext, + StableElementKey referenceKey, + ASTCDType reference, + ASTCDType concrete) { + if (!context.useCommonParentForMultipleIncarnations()) { + return false; + } + boolean referenceClassConcreteInterface = + reference instanceof ASTCDClass && concrete instanceof ASTCDInterface; + boolean referenceInterfaceConcreteClass = + reference instanceof ASTCDInterface && concrete instanceof ASTCDClass; + if (referenceClassConcreteInterface) { + return true; + } + if (!referenceInterfaceConcreteClass) { + return false; + } + if (incarnationContext.getGroupingFor(StableElementKey.type(concrete.getName())).isPresent()) { + return true; + } + Set mappedConcreteTypes = new LinkedHashSet<>(); + for (var incarnation : incarnationContext.getIncarnations(referenceKey)) { + mappedConcreteTypes.add(incarnation.key().getName()); + } + for (String parentName : context.concreteParentNames(concrete)) { + if (mappedConcreteTypes.contains(parentName)) { + return true; + } + } + return !context.concreteParentNames(concrete).isEmpty(); + } + + private void validateFieldTargets( + ConflictCollector conflicts, + String mapping, + StableElementKey reference, + List targets) { + Map byOwnerAndName = new LinkedHashMap<>(); + for (StableElementKey target : targets) { + String key = target.getOwnerType().orElse("") + "." + target.getName(); + String type = target.getFieldKind().orElse("Object"); + String previous = byOwnerAndName.putIfAbsent(key, type); + if (previous != null && !previous.equals(type)) { + conflicts.conflict( + mapping, + "field target conflict", + reference.signature() + " maps to incompatible concrete fields " + targets); + } + } + } + + private void validateMethodTargets( + ConflictCollector conflicts, + String mapping, + StableElementKey reference, + List targets) { + Map bySignature = new LinkedHashMap<>(); + for (StableElementKey target : targets) { + String signature = target.signature(); + String returnType = target.getReturnType().orElse("void"); + String previous = bySignature.putIfAbsent(signature, returnType); + if (previous != null && !previous.equals(returnType)) { + conflicts.conflict( + mapping, + "method target conflict", + reference.signature() + " maps to incompatible concrete methods " + targets); + } + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/UnderspecifiedTypeConflictCheck.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/UnderspecifiedTypeConflictCheck.java new file mode 100644 index 00000000..d4209474 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/multiIncarnation/conflict/UnderspecifiedTypeConflictCheck.java @@ -0,0 +1,105 @@ +package de.monticore.codeAdaption.handler.multiIncarnation.conflict; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._ast.ASTCDParameter; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.utils.JavaLoader; + +final class UnderspecifiedTypeConflictCheck implements AdaptationConflictCheck { + + @Override + public void check(ConflictDetectionContext context, ConflictCollector conflicts) { + for (String mapping : context.mappings()) { + IncarnationContext incarnationContext = context.contexts().get(mapping); + if (incarnationContext == null) { + continue; + } + for (ASTCDType referenceType : context.referenceTypes().values()) { + boolean ownerMapped = + !incarnationContext.getIncarnations(StableElementKey.type(referenceType.getName())).isEmpty(); + if (!ownerMapped) { + continue; + } + for (ASTCDAttribute attribute : referenceType.getCDAttributeList()) { + if (context.isAny(JavaLoader.print(attribute.getMCType())) + && incarnationContext + .getIncarnations(StableElementKey.field(referenceType, attribute)) + .isEmpty() + && !hasMappedForEachDerivative( + context, incarnationContext, referenceType, attribute)) { + conflicts.conflict( + mapping, + "underspecified attribute type", + referenceType.getName() + "." + attribute.getName() + + " uses any without a concrete incarnation"); + } + } + for (ASTCDMethod method : referenceType.getCDMethodList()) { + boolean methodMapped = + !incarnationContext.getIncarnations(StableElementKey.method(referenceType, method)).isEmpty(); + if (context.isAny(JavaLoader.print(method.getMCReturnType())) + && !methodMapped + && !hasMappedForEachDerivative(context, incarnationContext, referenceType, method)) { + conflicts.conflict( + mapping, + "underspecified method return type", + referenceType.getName() + "." + method.getName() + + " returns any without a concrete incarnation"); + } + for (ASTCDParameter parameter : method.getCDParameterList()) { + if (context.isAny(JavaLoader.print(parameter.getMCType())) && !methodMapped) { + conflicts.conflict( + mapping, + "underspecified method parameter type", + referenceType.getName() + "." + method.getName() + + " has parameter " + + parameter.getName() + + " of type any"); + } + } + } + } + } + } + + private boolean hasMappedForEachDerivative( + ConflictDetectionContext context, + IncarnationContext incarnationContext, + ASTCDType owner, + ASTCDMethod target) { + String qualifiedTarget = owner.getName() + "." + target.getName(); + for (ASTCDAttribute attribute : owner.getCDAttributeList()) { + if (context.forEachValue(attribute) + .filter(value -> value.equals(target.getName()) || value.endsWith(qualifiedTarget)) + .isPresent() + && !incarnationContext + .getIncarnations(StableElementKey.field(owner, attribute)) + .isEmpty()) { + return true; + } + } + return false; + } + + private boolean hasMappedForEachDerivative( + ConflictDetectionContext context, + IncarnationContext incarnationContext, + ASTCDType owner, + ASTCDAttribute target) { + String qualifiedTarget = owner.getName() + "." + target.getName(); + for (ASTCDAttribute attribute : owner.getCDAttributeList()) { + if (context.forEachValue(attribute) + .filter(value -> value.equals(target.getName()) || value.equals(qualifiedTarget)) + .isPresent() + && !incarnationContext + .getIncarnations(StableElementKey.field(owner, attribute)) + .isEmpty()) { + return true; + } + } + return false; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/CodeMatching.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/CodeMatching.java index f557fe9f..998226f2 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/CodeMatching.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/CodeMatching.java @@ -4,26 +4,31 @@ import java.util.ArrayList; import java.util.List; -/*** - * Save matching information, each Matching is attached to an element (type,field,method,..) of - * the reference code. - * It saves the necessary implementation to build the concrete name of this element. +/** + * Describes how one handwritten Java element is related to elements of the reference CD. + * + *

The {@linkplain #getReferences() references} are reference-CD symbols, not concrete + * incarnations. During adaptation, they are resolved to concrete incarnations and inserted, in + * list order, into {@linkplain #getTemplate() the naming template}. For example, references + * {@code [Entity, Entity.id]} and template {@code find${}By${cap_first}} can produce {@code + * findPersonByNumber} when {@code Entity -> Person} and {@code id -> number}. + * + *

A matching may instead represent an explicit {@code @Adapt(ignore = true)} instruction. In + * that case {@link #mustBePerform()} returns {@code false}: the element remains relevant to + * filtering, but no adaptation is performed on it. */ public class CodeMatching { - /*** - * is true when the code element has to be ignored during the adaptation. - */ + /** Whether the matched Java element is intentionally excluded from adaptation. */ private boolean ignore = false; + private boolean explicitAnnotation; - /*** - * CD-references of the element - */ + /** Reference-CD symbols consumed by the naming templates, in placeholder order. */ private final List references = new ArrayList<>(); - /*** - * must be field with the concrete as argument reference to build the new name - */ + /** Template for adapting an existing handwritten name. */ private String template; + /** Optional template used when generating a new declaration. */ + private String generateTemplate; public CodeMatching(boolean ignore) { this.ignore = ignore; @@ -31,14 +36,21 @@ public CodeMatching(boolean ignore) { public CodeMatching() {} + /** Returns the mutable, placeholder-ordered list of reference-CD symbols. */ public List getReferences() { return references; } + /** Returns the template used to adapt an existing handwritten name. */ public String getTemplate() { return template; } + /** Returns the optional generation template, or {@code null} when none was configured. */ + public String getGenerateTemplate() { + return generateTemplate; + } + public void addReference(ISymbol reference) { this.references.add(reference); } @@ -47,11 +59,25 @@ public void setTemplate(String template) { this.template = template; } + public void setGenerateTemplate(String generateTemplate) { + this.generateTemplate = generateTemplate; + } + public void setIgnore(boolean ignore) { this.ignore = ignore; } + /** Returns whether this matching requests adaptation rather than explicit exclusion. */ public boolean mustBePerform() { return !ignore; } + + public void setExplicitAnnotation(boolean explicitAnnotation) { + this.explicitAnnotation = explicitAnnotation; + } + + /** Returns whether this matching originated from an explicit {@code @Adapt} annotation. */ + public boolean isExplicitAnnotation() { + return explicitAnnotation; + } } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/MatcherHelper.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/MatcherHelper.java index b96c9d38..a0bea377 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/MatcherHelper.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/MatcherHelper.java @@ -1,13 +1,14 @@ package de.monticore.codeAdaption.matcher; import static de.monticore.codeAdaption.utils.Constants.*; -import static de.monticore.codeAdaption.utils.Constants.PLACE_HOLDER_REGEX; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.cdbasis._ast.ASTCDType; import de.monticore.codeAdaption.matcher.annotMatcher.AnnotElementCollector; +import de.monticore.codeAdaption.utils.AdaptAnnotationNames; import de.monticore.codeAdaption.utils.AdapterUtils; import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.JavaSourceNames; import de.monticore.java.javadsl.JavaDSLMill; import de.monticore.java.javadsl._ast.ASTJavaAnnotation; import de.monticore.java.javadsl._visitor.JavaDSLTraverser; @@ -15,17 +16,24 @@ import de.monticore.statements.mccommonstatements._ast.ASTJavaModifier; import de.monticore.statements.mcstatementsbasis._ast.ASTMCModifier; import de.monticore.symboltable.ISymbol; +import de.se_rwth.commons.logging.Log; import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; -/*** - * helper functions of the matcher. - */ -public class MatcherHelper { +/** Creates matching results and applies the naming templates shared by matcher strategies. */ +public final class MatcherHelper { + private MatcherHelper() {} + + /** + * Creates an executable matching from a name template and its ordered reference symbols. + * + * @param template template later expanded with concrete incarnation names + * @param references symbols consumed by the template in encounter order + * @return non-ignored matching ready for name generation + */ public static CodeMatching mkMatching(String template, List references) { CodeMatching matching = new CodeMatching(); @@ -35,6 +43,10 @@ public static CodeMatching mkMatching(String template, List references) return matching; } + /** + * Decodes one {@code @Adapt} annotation into a matching and resolves its textual references in + * the supplied reference CD. Unresolvable references are warned about and omitted. + */ public static CodeMatching mkMatchingFromAnnotation( ASTMCModifier annotation, ASTCDCompilationUnit cd) { // init visitor and traverser @@ -45,19 +57,29 @@ public static CodeMatching mkMatchingFromAnnotation( // build matching CodeMatching matching = new CodeMatching(); + matching.setExplicitAnnotation(true); matching.setTemplate(collector.getTemplate()); + matching.setGenerateTemplate(collector.getGenTemplate()); matching.setIgnore(collector.isIgnore()); // resolve and add reference to the matching for (String ref : collector.getReferences()) { Optional symbol = AdapterUtils.resolveCDSymbol(ref, cd); - assert symbol.isPresent(); - matching.addReference(symbol.get()); + if (symbol.isPresent()) { + matching.addReference(symbol.get()); + } else { + Log.warn(String.format("MatcherHelper: could not resolve annotation reference '%s' in reference CD. Skipping this reference.", ref)); + } } return matching; } + /** + * Creates an infix-based matching when at least one candidate symbol occurs in the source name. + * Redundant references are removed before the replacement template and positional symbol order + * are calculated. + */ public static Optional mkMatchingFromInfixRef( List references, String srcName) { @@ -71,10 +93,20 @@ public static Optional mkMatchingFromInfixRef( return Optional.empty(); } + /** + * Replaces occurrences of reference names in a source identifier with matcher placeholders while + * preserving whether the occurrence starts with upper or lower case. + * + *

For example, reference {@code Person} turns {@code PersonRepository} into + * {@code ${}Repository} and {@code personRepository} into {@code ${uncap_first}Repository}. + */ public static String mkTemplateFormInfix(String name, List infixList) { String template = name; - for (ISymbol infixSymbol : infixList) { + List orderedInfixes = new ArrayList<>(infixList); + orderedInfixes.sort( + Comparator.comparingInt((ISymbol symbol) -> symbol.getName().length()).reversed()); + for (ISymbol infixSymbol : orderedInfixes) { String infix = infixSymbol.getName(); if (name.contains(infix)) { template = template.replace(infix, SIMPLE_PLACE_HOLDER); @@ -89,86 +121,128 @@ public static String mkTemplateFormInfix(String name, List infixList) { return template; } + /** + * Selects non-overlapping reference-name occurrences and returns their symbols in source order. + * Longer candidate names win when two candidates overlap. + * + *

For {@code UserRepositoryFactory} with candidates {@code User}, {@code Repository}, and + * {@code UserRepository}, the result starts with {@code UserRepository}; the overlapping + * {@code User} and {@code Repository} candidates are omitted. + */ public static List cleanReferences(String name, List infixList) { - List refs = - infixList.stream().map(ref -> ref.getName().toLowerCase()).collect(Collectors.toList()); - Map refMap = new LinkedHashMap<>(); - - for (int i = 0; i < refs.size(); i++) { - refMap.put(name.toLowerCase().indexOf(refs.get(i)), infixList.get(i)); - } - - List result = new ArrayList<>(); - for (int i = 0; i < name.length(); i++) { - if (refMap.containsKey(i)) { - result.add(refMap.get(i)); + String lowerName = name.toLowerCase(Locale.ROOT); + Map> refsByPosition = new TreeMap<>(); + List longestFirst = new ArrayList<>(infixList); + longestFirst.sort( + Comparator.comparingInt((ISymbol symbol) -> symbol.getName().length()).reversed()); + // Prefer longer symbols and reserve their character ranges. Ordinary substring helpers can + // locate occurrences, but they do not provide this deterministic non-overlap policy. + boolean[] occupied = new boolean[name.length()]; + for (ISymbol reference : longestFirst) { + String infix = reference.getName().toLowerCase(Locale.ROOT); + if (infix.isEmpty()) { + continue; + } + int from = 0; + while (from <= lowerName.length() - infix.length()) { + int index = lowerName.indexOf(infix, from); + if (index < 0) { + break; + } + boolean overlaps = false; + for (int i = index; i < index + infix.length(); i++) { + overlaps |= occupied[i]; + } + if (!overlaps) { + refsByPosition.computeIfAbsent(index, ignored -> new ArrayList<>()).add(reference); + Arrays.fill(occupied, index, index + infix.length(), true); + } + from = index + infix.length(); } } + List result = new ArrayList<>(); + refsByPosition.values().forEach(result::addAll); return result; } + /** Returns the adapter annotation among JavaDSL Java modifiers, if present. */ public static Optional getInfoJavaAnnot(List mods) { - for (ASTMCModifier mod : mods) { + for (ASTJavaModifier mod : mods) { if (mod instanceof ASTJavaAnnotation - && ((ASTJavaAnnotation) mod).getAnnotationName().getQName().equals(ANNOT_NAME)) { + && AdaptAnnotationNames.matches( + ((ASTJavaAnnotation) mod).getAnnotationName().getQName())) { return Optional.of((ASTJavaAnnotation) mod); } } return Optional.empty(); } + /** Returns the adapter annotation among JavaLight modifiers, if present. */ public static Optional getInfoAnnotation(List mods) { for (ASTMCModifier mod : mods) { if (mod instanceof ASTAnnotation - && ((ASTAnnotation) mod).getAnnotationName().getQName().equals(ANNOT_NAME)) { + && AdaptAnnotationNames.matches(((ASTAnnotation) mod).getAnnotationName().getQName())) { return Optional.of((ASTAnnotation) mod); } } return Optional.empty(); } - /*** - * fill template with the reference. - * @param template the template. - * @param refSymbol the template arguments - * @return the generated String. + /** + * Replaces matcher placeholders with reference-symbol names from left to right. + * + *

{@code ${}} inserts the symbol name, {@code ${cap_first}} capitalizes its first character, + * and {@code ${uncap_first}} lowercases its first character. Every placeholder consumes one + * symbol. Placeholders without a corresponding symbol remain unchanged. + * + * @param template the validation or generation name template + * @param refSymbol reference symbols consumed in placeholder order + * @return the expanded template, or the original value for null/empty inputs */ public static String fillTemplate(String template, List refSymbol) { - StringBuilder builder = new StringBuilder(template); - - // Create a pattern to match everything between "${" and "}" + if (template == null || template.isEmpty() || refSymbol == null || refSymbol.isEmpty()) { + return template; + } Pattern pattern = Pattern.compile(PLACE_HOLDER_REGEX); Matcher matcher = pattern.matcher(template); - - for (ISymbol feld : refSymbol) { - if (matcher.find()) { - String pHolder = matcher.group(1); - - String replacement; - if (pHolder.equals(CAP_FIRST)) { - replacement = capFirst(feld.getName()); - } else if (pHolder.equals(UNCAP_FIRST)) { - replacement = uncapFirst(feld.getName()); - } else { - replacement = feld.getName(); - } - builder = - new StringBuilder(builder.toString().replaceFirst(PLACE_HOLDER_REGEX, replacement)); + StringBuffer result = new StringBuffer(); + int referenceIndex = 0; + while (matcher.find()) { + if (referenceIndex >= refSymbol.size()) { + matcher.appendReplacement(result, Matcher.quoteReplacement(matcher.group(0))); + continue; + } + ISymbol field = refSymbol.get(referenceIndex++); + String pHolder = matcher.group(1); + String replacement; + if (pHolder.equals(CAP_FIRST)) { + replacement = capFirst(field.getName()); + } else if (pHolder.equals(UNCAP_FIRST)) { + replacement = uncapFirst(field.getName()); + } else { + replacement = field.getName(); } + matcher.appendReplacement(result, Matcher.quoteReplacement(replacement)); } - - return builder.toString(); + matcher.appendTail(result); + return result.toString(); } + /** Returns {@code str} with its first character upper-cased, preserving null and empty values. */ public static String capFirst(String str) { - return Character.toUpperCase(str.charAt(0)) + str.substring(1); + return JavaSourceNames.capitalize(str); } + /** Returns {@code str} with its first character lower-cased, preserving null and empty values. */ public static String uncapFirst(String str) { - return Character.toLowerCase(str.charAt(0)) + str.substring(1); + return JavaSourceNames.uncapitalize(str); } + /** + * Resolves CD type symbols whose names occur both in a variable name and its declared Java type. + * This avoids treating a type mentioned only in a generic declaration as a variable-name match. + */ public static List resolveReferencesFromType( String varName, ASTMCType type, ASTCDCompilationUnit cd) { @@ -184,23 +258,33 @@ public static List resolveReferencesFromType( return refList; } + /** + * Removes duplicate symbols and shorter names contained in longer reference names. The returned + * list is a copy and the input collection is never mutated. + */ public static List cleanReferences(List references) { if (references.isEmpty() || references.size() == 1) { - return references; + return new ArrayList<>(references); } - Set temps = new LinkedHashSet<>(references); - for (ISymbol symbol : temps) { - for (ISymbol symbol1 : temps) { - if (!symbol.equals(symbol1) && (matchInfix(symbol.getName(), symbol1.getName()))) { - references.remove(symbol1); + // Remove duplicates first, then remove shorter reference names embedded in longer references; + // for example, User is redundant when UserRepository is already a reference. + List result = new ArrayList<>(new LinkedHashSet<>(references)); + List snapshot = new ArrayList<>(result); + for (ISymbol symbol : snapshot) { + for (ISymbol other : snapshot) { + if (!symbol.equals(other) + && symbol.getName().length() > other.getName().length() + && matchInfix(symbol.getName(), other.getName())) { + result.remove(other); } } } - return references; + return result; } + /** Performs a locale-independent, case-insensitive infix test. */ public static boolean matchInfix(String element, String infix) { - return element.toLowerCase().contains(infix.toLowerCase()); + return element.toLowerCase(Locale.ROOT).contains(infix.toLowerCase(Locale.ROOT)); } } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTMemberMatcher.java index f5553f57..1399be0a 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTMemberMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTMemberMatcher.java @@ -1,5 +1,7 @@ package de.monticore.codeAdaption.matcher.NameMatcher; +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._ast.ASTCDParameter; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.cdbasis._ast.ASTCDType; import de.monticore.codeAdaption.matcher.CodeMatching; @@ -8,6 +10,7 @@ import de.monticore.codeAdaption.matcher.TypeMatcher; import de.monticore.codeAdaption.utils.AdapterUtils; import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.JavaSourceNames; import de.monticore.java.javadsl._ast.ASTFieldDeclaration; import de.monticore.java.javadsl._ast.ASTTypeDeclaration; import de.monticore.javalight._ast.ASTMethodDeclaration; @@ -16,22 +19,30 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; -/*** - * match Field and method in the code with attribute and method in the class diagram - * having the same name. +/** + * Matches handwritten members by names within the reference-CD types represented by their Java + * owner. + * + *

Fields require one equal-name attribute. Methods require the same name and normalized + * parameter types, so {@code update()} and {@code update(String)} remain distinct. Declared + * supertypes use embedded type-name matching because their printed Java type may be qualified or + * generic rather than a bare simple name. */ public class NameTMemberMatcher implements TMemberMatcher { protected TypeMatcher typeMatcher; protected ASTCDCompilationUnit cd; + private List referenceTypes; public NameTMemberMatcher(ASTCDCompilationUnit cd) { - this.cd = cd; + setReferenceCD(cd); } @Override public void setReferenceCD(ASTCDCompilationUnit cd) { this.cd = cd; + this.referenceTypes = List.copyOf(AdapterUtils.getAllCDTypes(cd)); } @Override @@ -47,7 +58,8 @@ public TypeMatcher getTypeMatcher() { @Override public Optional getMatchedMethod( ASTTypeDeclaration type, ASTMethodDeclaration method) { - List references = resolveMethodReferencesOf(type, method.getName(), String::equals); + List parameterTypes = getMethodParameterTypes(method); + List references = resolveMethodReferencesBySignature(type, method.getName(), parameterTypes); if (references.size() == 1) { return Optional.of(MatcherHelper.mkMatching("${}", references)); @@ -56,9 +68,56 @@ public Optional getMatchedMethod( return Optional.empty(); } - /*** - * match a field in referring classes with the same name. - * example :field "id" in "EntityBuilder" refers to "id" in Entity. + private List getMethodParameterTypes(ASTMethodDeclaration method) { + if (!method.getFormalParameters().isPresentFormalParameterListing()) { + return new ArrayList<>(); + } + return method.getFormalParameters().getFormalParameterListing().getFormalParameterList().stream() + .map(p -> JavaSourceNames.normalizeType(JavaLoader.print(p.getMCType()))) + .collect(Collectors.toList()); + } + + private List resolveMethodReferencesBySignature( + ASTTypeDeclaration type, String methodName, List parameterTypes) { + + List references = new ArrayList<>(); + Optional matching = getTypeMatcher().getMatchedType(type); + + if (matching.isEmpty()) { + return references; + } + + for (ISymbol symbol : matching.get().getReferences()) { + if (symbol.getAstNode() instanceof ASTCDType) { + ASTCDType cdType = (ASTCDType) symbol.getAstNode(); + for (ASTCDMethod cdMethod : cdType.getCDMethodList()) { + if (cdMethod.getName().equals(methodName)) { + List cdParameterTypes = cdMethod.getCDParameterList().stream() + .map(ASTCDParameter::getMCType) + .map(JavaLoader::print) + .map(JavaSourceNames::normalizeType) + .collect(Collectors.toList()); + + if (parameterTypes.equals(cdParameterTypes)) { + references.add(cdMethod.getSymbol()); + } + } + } + } + } + return references; + } + + private int getMethodParameterCount(ASTMethodDeclaration method) { + if (!method.getFormalParameters().isPresentFormalParameterListing()) { + return 0; + } + return method.getFormalParameters().getFormalParameterListing().getFormalParameterList().size(); + } + + /** + * Matches one equal-name reference attribute within the Java owner's matched reference types. + * For example, field {@code id} in {@code EntityBuilder} may refer to attribute {@code Entity.id}. */ @Override public Optional getMatchedField( @@ -78,7 +137,7 @@ public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMC List references = new ArrayList<>(); String srcName = JavaLoader.print(supertype); // collect type reference in the class diagram - for (ASTCDType astcdType : AdapterUtils.getAllCDTypes(cd)) { + for (ASTCDType astcdType : referenceTypes) { if (srcName.toLowerCase().contains(astcdType.getName().toLowerCase())) { references.add(astcdType.getSymbol()); } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTypeMatcher.java index b683b6fc..3ea7aceb 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTypeMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTypeMatcher.java @@ -11,12 +11,14 @@ import java.util.Optional; import java.util.Set; -/*** - * match a type in the code with a type with a type with the same name - * in the reference class diagram. +/** + * Matches a handwritten type to the reference-CD type having the same case-sensitive simple name. + * For example, Java type {@code Entity} matches CD type {@code Entity}, while {@code + * EntityRepository} is left to the infix strategy. */ public class NameTypeMatcher implements TypeMatcher { protected ASTCDCompilationUnit cd; + private List referenceTypes; protected Set typeDeclarationSet; @@ -31,20 +33,19 @@ public void setAllTypeDeclarations(Set typeDeclarationSet) { } public NameTypeMatcher(ASTCDCompilationUnit cd) { - this.cd = cd; + setReferenceCD(cd); } @Override public void setReferenceCD(ASTCDCompilationUnit cd) { this.cd = cd; + this.referenceTypes = List.copyOf(AdapterUtils.getAllCDTypes(cd)); } - /*** - * match a type to a type with the same name in the class diagram. - */ + /** Returns an identity-template matching for one equal Java/CD type name. */ @Override public Optional getMatchedType(ASTTypeDeclaration element) { - for (ASTCDType type : AdapterUtils.getAllCDTypes(cd)) { + for (ASTCDType type : referenceTypes) { if (element.getName().equals(type.getName())) { return Optional.of(MatcherHelper.mkMatching("${}", List.of(type.getSymbol()))); } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TMemberMatcher.java index f921a331..e20fe41d 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TMemberMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TMemberMatcher.java @@ -12,19 +12,27 @@ import java.util.*; import java.util.function.BiFunction; +/** Strategy for owner-aware matching of Java fields, methods, and supertype references. */ public interface TMemberMatcher { + /** Sets the reference CD used by subsequent matching requests. */ void setReferenceCD(ASTCDCompilationUnit cd); + /** Sets the type matcher used to resolve the reference owner of a Java member. */ void setTypeMatcher(TypeMatcher matcher); + /** Returns the type matcher that establishes member ownership. */ TypeMatcher getTypeMatcher(); + /** Matches a Java method beneath its Java/reference owner. */ Optional getMatchedMethod(ASTTypeDeclaration type, ASTMethodDeclaration method); + /** Matches a Java field beneath its Java/reference owner. */ Optional getMatchedField(ASTTypeDeclaration type, ASTFieldDeclaration field); + /** Matches a declared Java superclass or interface reference. */ Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType supertype); + /** Resolves matching CD attributes from every reference type represented by the Java owner. */ default List resolveFieldReferencesOf( ASTTypeDeclaration type, String name, BiFunction match) { @@ -47,8 +55,18 @@ default List resolveFieldReferencesOf( return references; } + /** Resolves matching CD methods without restricting overload arity. */ default List resolveMethodReferencesOf( ASTTypeDeclaration type, String name, BiFunction match) { + return resolveMethodReferencesOf(type, name, match, -1); // -1 - ignore parameter count + } + + /** + * Resolves matching CD methods, optionally requiring an exact parameter count when {@code + * paramCount >= 0}. + */ + default List resolveMethodReferencesOf( + ASTTypeDeclaration type, String name, BiFunction match, int paramCount) { List references = new ArrayList<>(); Optional matching = getTypeMatcher().getMatchedType(type); @@ -57,17 +75,22 @@ default List resolveMethodReferencesOf( return references; } - // resolve attribute reference in referencing types + // resolve method reference in referencing types for (ISymbol symbol : matching.get().getReferences()) { - for (ASTCDMethod att : ((ASTCDType) symbol.getAstNode()).getCDMethodList()) { - if (match.apply(name, att.getName())) { - references.add(att.getSymbol()); + for (ASTCDMethod cdMethod : ((ASTCDType) symbol.getAstNode()).getCDMethodList()) { + if (match.apply(name, cdMethod.getName())) { + // If paramCount is specified, also check parameter count for overloaded methods + if (paramCount >= 0 && cdMethod.getCDParameterList().size() != paramCount) { + continue; // Skip methods with different parameter counts + } + references.add(cdMethod.getSymbol()); } } } return references; } + /** Resolves matched reference types represented directly by the Java owner. */ default List resolveTypeReferencesOf( ASTTypeDeclaration type, String name, BiFunction match) { diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TypeMatcher.java index 7299d70d..fbc100d3 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TypeMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TypeMatcher.java @@ -5,17 +5,22 @@ import java.util.Optional; import java.util.Set; -/*** - * this interface validates and cleans a reference code for a given reference model. - * it also collects the necessary update operation for an adaptation. - */ - +/** Strategy for mapping Java type declarations to elements of one reference class diagram. */ public interface TypeMatcher { + /** Sets the reference CD used by subsequent matching requests. */ void setReferenceCD(ASTCDCompilationUnit cd); + /** Returns all Java type declarations currently visible to cross-type matching. */ Set getAllTypeDeclarations(); + /** Replaces the Java type declarations visible to cross-type matching. */ void setAllTypeDeclarations(Set typeDeclarations); + /** + * Matches one Java type. + * + * @return a matching (including explicit ignore results), or empty when this strategy does not + * apply + */ Optional getMatchedType(ASTTypeDeclaration type); } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/VariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/VariableMatcher.java index 72346a1c..a834fc7d 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/VariableMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/VariableMatcher.java @@ -7,12 +7,16 @@ import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; import java.util.Optional; +/** Strategy for matching Java local variables and formal parameters within a matched method. */ public interface VariableMatcher { + /** Sets the reference CD used by subsequent matching requests. */ void setReferenceCD(ASTCDCompilationUnit cd); + /** Matches one local variable in its owning Java type and method. */ Optional getMatchedLocalVariable( ASTTypeDeclaration type, ASTMethodDeclaration method, ASTLocalVariableDeclaration locVar); + /** Matches one formal parameter in its owning Java type and method. */ Optional getMatchedFormalParameter( ASTTypeDeclaration type, ASTMethodDeclaration method, ASTFormalParameter param); } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotElementCollector.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotElementCollector.java index 26bb3111..57289fcd 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotElementCollector.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotElementCollector.java @@ -1,8 +1,6 @@ package de.monticore.codeAdaption.matcher.annotMatcher; import de.monticore.codeAdaption.utils.Constants; -import de.monticore.expressions.expressionsbasis._ast.ASTExpression; -import de.monticore.expressions.expressionsbasis._ast.ASTLiteralExpression; import de.monticore.java.javadsl.JavaDSLMill; import de.monticore.java.javadsl._visitor.JavaDSLTraverser; import de.monticore.javalight._ast.ASTElementValueOrExpr; @@ -14,13 +12,18 @@ import java.util.ArrayList; import java.util.List; -/*** - * this class visits an ASTAnnotation or ASTJavaAnnotation and collects information. - * (template, ignore-tag and references) +/** + * Decodes the literal attributes of one JavaDSL {@code @Adapt} annotation. + * + *

{@code ref} values are collected in declaration order because template placeholders consume + * them from left to right. {@code template} and {@code genTemplate} must each contain exactly one + * string literal, while {@code ignore} must contain exactly one boolean literal. Structural and + * reference-resolution validation is performed later by {@code ValidAnnotation}. */ public class AnnotElementCollector implements JavaLightVisitor2 { private String template; + private String genTemplate; private final List references = new ArrayList<>(); private boolean ignore; @@ -28,28 +31,65 @@ public class AnnotElementCollector implements JavaLightVisitor2 { public void visit(ASTElementValuePair node) { if (node.getName().equals(Constants.TEMPLATE)) { - ASTExpression val = node.getElementValueOrExpr().getExpression(); - template = ((ASTStringLiteral) ((ASTLiteralExpression) val).getLiteral()).getValue(); + template = readSingleString(node.getElementValueOrExpr(), Constants.TEMPLATE); } if (node.getName().equals(Constants.IGNORE)) { - ASTExpression val = node.getElementValueOrExpr().getExpression(); - ignore = ((ASTBooleanLiteral) ((ASTLiteralExpression) val).getLiteral()).getValue(); + ignore = readSingleBoolean(node.getElementValueOrExpr(), Constants.IGNORE); } if (node.getName().equals(Constants.REFERENCE)) { - ASTElementValueOrExpr val = node.getElementValueOrExpr(); - MCCommonLiteralsVisitor2 visitor = - new MCCommonLiteralsVisitor2() { - @Override - public void visit(ASTStringLiteral node) { - references.add(node.getValue()); - } - }; - JavaDSLTraverser traverser = JavaDSLMill.traverser(); - traverser.add4MCCommonLiterals(visitor); - val.accept(traverser); + references.addAll(readStrings(node.getElementValueOrExpr())); } + + if (node.getName().equals(Constants.GENERATE_TEMPLATE)) { + genTemplate = readSingleString(node.getElementValueOrExpr(), Constants.GENERATE_TEMPLATE); + } + } + + private static String readSingleString(ASTElementValueOrExpr value, String attribute) { + List strings = readStrings(value); + if (strings.size() != 1) { + throw new IllegalArgumentException( + "@Adapt attribute '" + attribute + "' requires exactly one string literal"); + } + return strings.get(0); + } + + private static boolean readSingleBoolean(ASTElementValueOrExpr value, String attribute) { + List booleans = new ArrayList<>(); + MCCommonLiteralsVisitor2 visitor = + new MCCommonLiteralsVisitor2() { + @Override + public void visit(ASTBooleanLiteral node) { + booleans.add(node.getValue()); + } + }; + traverse(value, visitor); + if (booleans.size() != 1) { + throw new IllegalArgumentException( + "@Adapt attribute '" + attribute + "' requires exactly one boolean literal"); + } + return booleans.get(0); + } + + private static List readStrings(ASTElementValueOrExpr value) { + List strings = new ArrayList<>(); + MCCommonLiteralsVisitor2 visitor = + new MCCommonLiteralsVisitor2() { + @Override + public void visit(ASTStringLiteral node) { + strings.add(node.getValue()); + } + }; + traverse(value, visitor); + return strings; + } + + private static void traverse(ASTElementValueOrExpr value, MCCommonLiteralsVisitor2 visitor) { + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4MCCommonLiterals(visitor); + value.accept(traverser); } public List getReferences() { @@ -60,6 +100,10 @@ public String getTemplate() { return template; } + public String getGenTemplate() { + return genTemplate; + } + public boolean isIgnore() { return ignore; } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTMemberMatcher.java index 0710c2bf..bd772e45 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTMemberMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTMemberMatcher.java @@ -12,9 +12,11 @@ import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.util.Optional; -/*** - * match an Attributes and method in the reference code to elements - * in the reference class Diagram form annotations. +/** + * Matches handwritten fields and methods through explicit {@code @Adapt} annotations. + * + *

Declared Java supertypes cannot carry annotations at their type-use position in the supported + * JavaDSL model, so this strategy deliberately returns no supertype match. */ public class AnnotTMemberMatcher implements TMemberMatcher { diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTypeMatcher.java index dfdb364c..5baaee91 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTypeMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTypeMatcher.java @@ -9,9 +9,10 @@ import java.util.Optional; import java.util.Set; -/*** - * match a TypeDeclaration(class, enum, interface) in the reference code to elements in - * the reference class Diagram form annotations. +/** + * Matches a handwritten class, interface, or enum through its explicit {@code @Adapt} annotation. + * Annotation references are resolved against the reference CD and retain their declared order for + * template expansion. */ public class AnnotTypeMatcher implements TypeMatcher { protected ASTCDCompilationUnit cd; diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotVariableMatcher.java index 3da61422..1697fa10 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotVariableMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotVariableMatcher.java @@ -11,9 +11,9 @@ import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; import java.util.Optional; -/*** - * match a methods parameters and local variables in the reference code to elements - * in the reference class Diagram form annotations. +/** + * Matches handwritten formal parameters and local variables through explicit {@code @Adapt} + * annotations whose references are resolved against the reference CD. */ public class AnnotVariableMatcher implements VariableMatcher { protected ASTCDCompilationUnit cd; @@ -23,7 +23,9 @@ public AnnotVariableMatcher(ASTCDCompilationUnit cd) { } @Override - public void setReferenceCD(ASTCDCompilationUnit cd) {} + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } @Override public Optional getMatchedLocalVariable( diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTMemberMatcher.java index e96714d0..370aef57 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTMemberMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTMemberMatcher.java @@ -11,9 +11,12 @@ import java.util.List; import java.util.Optional; -/*** - * compose matching Strategy for Method and attributes. - * allow trying several matching strategies until a matching is found. +/** + * Applies field, method, and supertype matchers in configured precedence order and returns the + * first result for the requested member. + * + *

The same enclosing-type matcher is shared with every member strategy so owner-relative + * lookups resolve against the same reference-CD types. */ public class CompTMemberMatcher implements TMemberMatcher { protected TypeMatcher typeMatcher; diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTypeMatcher.java index 92b06378..e5bc6d98 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTypeMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTypeMatcher.java @@ -8,9 +8,11 @@ import java.util.Optional; import java.util.Set; -/*** - * compose matching Strategy for Types. - * allow trying several matching strategies until a matching is found. +/** + * Applies type-matching strategies in configured precedence order and returns the first result. + * + *

A present ignored matching is still a result and stops the chain. The validator therefore + * installs annotation/name/infix strategies first and an ignore-or-error policy last. */ public class CompTypeMatcher implements TypeMatcher { protected List matchers; diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompVariableMatcher.java index a6d23994..b98ef150 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompVariableMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompVariableMatcher.java @@ -10,9 +10,9 @@ import java.util.List; import java.util.Optional; -/*** - * compose matching Strategy for functions parameters and local variables. - * allow trying several matching strategies until a matching is found. +/** + * Applies formal-parameter and local-variable matchers in configured precedence order and returns + * the first result. Annotation and infix strategies run before the terminal ignore-or-error policy. */ public class CompVariableMatcher implements VariableMatcher { diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTMemberMatcher.java index fa4e1b7d..6dd7d996 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTMemberMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTMemberMatcher.java @@ -13,8 +13,12 @@ import de.se_rwth.commons.logging.Log; import java.util.Optional; -/*** - *throws an error when the previous strategies didn't find machining for attributes or a methods. +/** + * Terminal fallback that reports unmatched fields, methods, and external supertypes as validation + * errors. + * + *

A supertype declared by another Java source in the same input batch is accepted unchanged: it + * is a source-local Java relationship rather than a missing reference-CD match. */ public class ErrorTMemberMatcher implements TMemberMatcher { protected ASTCDCompilationUnit cd; @@ -68,7 +72,6 @@ public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMC String pos = AdapterUtils.getPosition(supertype.get_SourcePositionStart()); Log.error(pos + " No Match found for the Type " + name); - assert false; return Optional.empty(); } } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTypeMatcher.java index c9e5ac09..11de733a 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTypeMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTypeMatcher.java @@ -9,8 +9,9 @@ import java.util.Optional; import java.util.Set; -/*** - *throws an error when the previous strategy didn't find machining for types +/** + * Terminal fallback that reports an unmatched Java type as a validation error. + * It is installed when {@code IGNORE_NON_MATCHED_TYPE} is not enabled. */ public class ErrorTypeMatcher implements TypeMatcher { protected ASTCDCompilationUnit cd; diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorVariableMatcher.java index e77ea23c..e01cb8ae 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorVariableMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorVariableMatcher.java @@ -11,9 +11,9 @@ import de.se_rwth.commons.logging.Log; import java.util.Optional; -/*** - *throws an error when the previous strategy didn't find machining for local-variables - * and method parameters. +/** + * Terminal fallback that reports unmatched local variables and formal parameters as validation + * errors. It is installed when {@code IGNORE_NON_MATCHED_VAR} is not enabled. */ public class ErrorVariableMatcher implements VariableMatcher { @Override diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTMemberMatcher.java index 246049bf..3263dcf2 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTMemberMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTMemberMatcher.java @@ -10,10 +10,12 @@ import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.util.Optional; -/*** - *return an empty-matching with the ignore flag set as true. - *when the previous strategy didn't find machining for attributes or methods. - *the adaption will ignore the corresponding element. +/** + * Terminal fallback that accepts unmatched fields, methods, and supertypes unchanged. + * + *

The ignored matching prevents a validation error and tells update phases not to transform the + * member. It is installed by {@code IGNORE_NON_MATCHED_TYPE_MEMBER} after all enabled member + * matching strategies. */ public class IgnoreTMemberMatcher implements TMemberMatcher { protected ASTCDCompilationUnit cd; diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTypeMatcher.java index 35edf46a..2931d9e9 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTypeMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTypeMatcher.java @@ -7,10 +7,13 @@ import java.util.Optional; import java.util.Set; -/*** - *Return an empty-matching with the ignore flag set as true. - *When the previous strategy didn't find machining for a type. - *The adaption will ignore the corresponding element. +/** + * Terminal fallback that accepts an unmatched Java type without adapting it. + * + *

The returned ignored matching prevents a validation error, but it does not invent a + * reference-CD incarnation. Consequently, an unmatched top-level type is not selected for + * mapping-specific adapted output. This matcher is installed by {@code IGNORE_NON_MATCHED_TYPE} + * after all enabled matching strategies. */ public class IgnoreTypeMatcher implements TypeMatcher { protected ASTCDCompilationUnit cd; diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreVariableMatcher.java index 9c58b1f3..6c803cb9 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreVariableMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreVariableMatcher.java @@ -9,10 +9,11 @@ import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; import java.util.Optional; -/*** - *Return an empty-matching with the ignore flag set as true. - *When the previous strategy didn't find machining for a local-variable or a method-parameter. - *The adaption will ignore the corresponding element. +/** + * Terminal fallback that accepts unmatched local variables and formal parameters unchanged. + * + *

It is installed by {@code IGNORE_NON_MATCHED_VAR} after all enabled variable matching + * strategies. */ public class IgnoreVariableMatcher implements VariableMatcher { @Override diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTMemberMatcher.java index 18746537..f1489c45 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTMemberMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTMemberMatcher.java @@ -14,9 +14,13 @@ import java.util.List; import java.util.Optional; -/*** - * match an Attributes and method in the reference code to elements - * in the reference class Diagram by analyzing the infix. +/** + * Matches handwritten fields, methods, and declared supertypes by reference-CD names embedded in + * their Java names or types. + * + *

For example, {@code getEntity()} may reference type {@code Entity}, while {@code getId()} may + * reference attribute {@code id}. Method candidates are additionally restricted by parameter + * count so overloads with different arity do not all become references. */ public class InfixTMemberMatcher implements TMemberMatcher { protected ASTCDCompilationUnit cd; @@ -41,27 +45,30 @@ public TypeMatcher getTypeMatcher() { return typeMatcher; } - /*** - * match method to a type or an attribute in the reference class diagram. - * eg: getId to id ; - * getEntity to Entity - */ + /** Matches a method name to embedded reference fields, types, and same-arity methods. */ @Override public Optional getMatchedMethod( ASTTypeDeclaration type, ASTMethodDeclaration method) { - // resolve references + // Get parameter count from the Java method for overloaded method matching + int paramCount = getMethodParameterCount(method); + + // resolve references with parameter count filtering for overloaded methods List references = resolveFieldReferencesOf(type, method.getName(), this::match); references.addAll(resolveTypeReferencesOf(type, method.getName(), this::match)); + references.addAll(resolveMethodReferencesOf(type, method.getName(), this::match, paramCount)); return MatcherHelper.mkMatchingFromInfixRef(references, method.getName()); } - /*** - * match field to a type or an attribute in the reference class diagram. - * eg: entityList to Entity - * longId to id - */ + private int getMethodParameterCount(ASTMethodDeclaration method) { + if (!method.getFormalParameters().isPresentFormalParameterListing()) { + return 0; + } + return method.getFormalParameters().getFormalParameterListing().getFormalParameterList().size(); + } + + /** Matches a field through reference names embedded in its name and declared type. */ @Override public Optional getMatchedField( ASTTypeDeclaration type, ASTFieldDeclaration field) { @@ -75,11 +82,7 @@ public Optional getMatchedField( return MatcherHelper.mkMatchingFromInfixRef(references, name); } - /*** - * match field to a type or an attribute in the reference class diagram. - * eg: entityList to Entity - * longId to id - */ + /** Matches a declared Java supertype to embedded reference-CD type names. */ @Override public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType superType) { String name = JavaLoader.print(superType); diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTypeMatcher.java index 582d9976..62923503 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTypeMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTypeMatcher.java @@ -13,9 +13,12 @@ import java.util.Optional; import java.util.Set; -/*** - * match a type in the reference code to elements - * in the reference class Diagram by analyzing the infix. +/** + * Matches a handwritten type when its name contains one or more reference-CD type names, + * case-insensitively. + * + *

For example, {@code EntityRepository} can reference {@code Entity}. When candidate names + * overlap, {@link MatcherHelper} gives longer matches precedence while building the template. */ public class InfixTypeMatcher implements TypeMatcher { protected ASTCDCompilationUnit cd; @@ -41,9 +44,7 @@ public void setReferenceCD(ASTCDCompilationUnit cd) { this.cd = cd; } - /*** - * match a type to a type in the class diagram with the same suffix. - */ + /** Returns an infix-derived matching for all reference-CD type names found in the Java name. */ @Override public Optional getMatchedType(ASTTypeDeclaration type) { List references = new ArrayList<>(); diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixVariableMatcher.java index 8f5b46d3..04cfcba1 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixVariableMatcher.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixVariableMatcher.java @@ -15,9 +15,12 @@ import java.util.List; import java.util.Optional; -/*** - * match a local-variable or a formal-parameter in the reference code to elements - * in the reference class Diagram by analyzing the infix. +/** + * Matches local variables and formal parameters from reference-CD names embedded in their Java + * identifier or declared type. + * + *

For example, {@code Entity currentEntity} may reference the CD type {@code Entity}; the + * resulting template preserves the surrounding identifier text. */ public class InfixVariableMatcher implements VariableMatcher { protected ASTCDCompilationUnit cd; diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdater.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdater.java index c804b8ae..8e1e5427 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdater.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdater.java @@ -1,6 +1,7 @@ package de.monticore.codeAdaption.updater; import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; import de.monticore.java.javadsl._ast.ASTFieldDeclaration; import de.monticore.java.javadsl._ast.ASTTypeDeclaration; import de.monticore.javalight._ast.ASTMethodDeclaration; @@ -9,57 +10,76 @@ import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.io.File; import java.nio.file.Path; +import java.util.List; +import java.util.Map; import java.util.Set; -/*** - * this class execute the update operation in the reference code. +/** + * Technology-neutral mutation facade used to transform one loaded handwritten Java model. + * + *

Implementations must update declarations and their uses consistently. Default methods fail + * explicitly when an implementation does not support a generation or cleanup capability. */ public interface CodeUpdater { - /*** - * set the path to the referenceCode. - * @param path the path. + /** + * Loads the Java source tree that subsequent operations mutate. + * + * @param path source directory */ void setCodePath(Path path); - /*** - * print the current state of the reference code as set of files. - * @return the code as files + /** + * Prints the current model into the configured output directory. + * + * @return generated Java files */ Set printCode(); - /*** - * change the name of a type in the reference code. By the declaration - * an all its reference an uses. - * @param srcType the source type to replace. - * @param newName the new name of the type. + /** + * Renames a type declaration and all resolvable references and uses. + * + * @param srcType handwritten Java declaration to rename + * @param newName concrete Java type name */ void updateType(ASTTypeDeclaration srcType, String newName); - /*** - * change the name of a method in the reference code. By the declaration - * an all its reference an uses. - * @param srcType the source-type that contains the method-declaration. - * @param srcMethod the source method. - * @param newName the new name of the type. + /** + * Renames a method declaration and the invocations resolved to that method. + * + * @param srcType handwritten Java type containing the method declaration + * @param srcMethod handwritten Java method to rename + * @param newName the new name of the method */ void updateMethod(ASTTypeDeclaration srcType, ASTMethodDeclaration srcMethod, String newName); - /*** - * change the name of a field in the reference code. By its declaration - * an all its references an uses. - * @param srcType the source-type that contains the field-declaration - * @param srcField the source Field. - * @param newName the new name of the field. + /** + * Renames a field declaration and all resolvable accesses. + * + * @param srcType handwritten Java type containing the field declaration + * @param srcField handwritten Java field to rename + * @param newName concrete field name */ void updateField(ASTTypeDeclaration srcType, ASTFieldDeclaration srcField, String newName); - /*** - * change the name of a local-variable in the reference code. By its declaration - * an all its references an uses. - * @param srcType the source-type that contains the local variable. - * @param srcMethod the source method tha contains le local variable. - * @param sourceVar the source local variable. - * @param newName the new name of the local variable. + /** + * Renames accesses to a field generated from a CD association role. + * + *

Unlike {@link #updateField}, this operation has no handwritten field declaration to rename: + * the declaration will be generated from the concrete CD. The source type scopes the rewrite so + * a role such as {@code children} on one owner does not affect another owner's same-named role. + */ + default void updateAssociationRole( + ASTTypeDeclaration srcType, String sourceRole, String concreteRole) { + throw unsupported("updateAssociationRole"); + } + + /** + * Renames a local variable declaration and all resolvable uses in its method. + * + * @param srcType handwritten Java type containing the local variable + * @param srcMethod handwritten Java method containing the local variable + * @param sourceVar local variable to rename + * @param newName concrete local-variable name */ void updateLocalVariable( ASTTypeDeclaration srcType, @@ -67,13 +87,13 @@ void updateLocalVariable( ASTLocalVariableDeclaration sourceVar, String newName); - /*** - * change the name of a local-variable in the reference code. By it declaration - * and all its references an uses - * @param srcType the source type that contains the local parameter - * @param srcMethod the source method that contains le the parameter - * @param srcParam the source parameter - * @param newName the new name of the parameter + /** + * Renames a method parameter declaration and all resolvable uses. + * + * @param srcType handwritten Java type containing the parameter + * @param srcMethod handwritten Java method containing the parameter + * @param srcParam formal parameter to rename + * @param newName concrete parameter name */ void updateMethodParameter( ASTTypeDeclaration srcType, @@ -81,17 +101,252 @@ void updateMethodParameter( ASTFormalParameter srcParam, String newName); - /*** - * Update all types that are not present in the reference code. - * @param cdType type in the reference class diagram to update in the reference code. - * @param newName new name of the type. + /** + * Rewrites uses of a reference-CD type that has no declaration in handwritten Java. + * + *

For example, handwritten code may declare {@code List} without declaring {@code Role} + * because that type is generated from the CD. If {@code Role} maps to {@code Permission}, this + * operation rewrites the type use even though {@link #updateType} has no Java declaration to + * target. + * + * @param cdType reference-CD type whose handwritten Java uses are rewritten + * @param newName concrete Java type name */ void updateCDType(ASTCDType cdType, String newName); - /*** - * set the output directory of the code by printing. + + /** + * Sets the destination used by {@link #printCode()}. + * * @param outputPath the output directory */ void setOutputDirectory(Path outputPath); + /** + * Renames one declared superclass or interface reference on a Java type. + * + * @param type Java type that owns the relationship + * @param supertype source supertype AST + * @param newName concrete supertype name + */ void updateSuperType(ASTTypeDeclaration type, ASTMCType supertype, String newName); + + /** + * Remove adapter-only metadata and perform implementation-specific post-processing on generated + * Java sources. + */ + default void cleanCode(Path codePath) { + throw unsupported("cleanCode"); + } + + /** + * Configures incarnation-type to grouping-type replacements for the current updater pass. + * + *

Keys identify individual concrete incarnations and values identify the common concrete type + * representing their incarnation group. For example, {@code {CreditCard=PaymentMethod, + * Invoice=PaymentMethod}} allows a shared {@code CreditCard} or {@code Invoice} parameter to be + * printed as {@code PaymentMethod}. Implementations apply these replacements during final model + * repair; they do not rename the incarnation declarations themselves. + * + * @param mappings incarnation simple name to grouping-type simple name; empty disables grouping + */ + default void setGroupingMappings(Map mappings) { + if (mappings != null && !mappings.isEmpty()) { + throw unsupported("setGroupingMappings"); + } + } + + /** + * Registers an owner-independent concrete method signature for legacy invocation repair. + * + *

For example, registering {@code send(String, boolean)} allows an adapted {@code send(label)} + * invocation to receive a compatible enclosing {@code boolean} parameter or a Java default value. + * Because no owner is supplied, repair is performed only when the method name has one + * unambiguous registered signature. New code should prefer {@link #registerMethodRewrite}. + * + * @param methodName concrete method name + * @param parameterTypes concrete parameter types in declaration order + */ + default void registerConcreteMethodSignature(String methodName, List parameterTypes) { + throw unsupported("registerConcreteMethodSignature"); + } + + /** + * Registers an owner- and signature-aware method rewrite for invocation repair. + * + *

The reference key identifies the method before adaptation; the concrete key identifies its + * renamed owner, name, and parameters afterward. For example, {@code Port.send(String) -> + * ShippingPort.ship(String, boolean)} both renames matching calls and supplies the additional + * argument without changing unrelated {@code send} overloads. + * + * @param referenceMethod owner- and signature-aware reference-CD method key + * @param concreteMethod owner- and signature-aware concrete-CD method key + */ + default void registerMethodRewrite(StableElementKey referenceMethod, StableElementKey concreteMethod) { + throw unsupported("registerMethodRewrite"); + } + + /** + * Add or complete a field on the target type. Implementations may clone the template field when + * present; completed-CD projection passes {@code null} when no Java template owns the member. + */ + default void addField( + ASTTypeDeclaration targetType, + ASTFieldDeclaration templateField, + String newName, + String newType, + boolean isStatic) { + throw unsupported("addField"); + } + + /** + * Add or complete a method on the target type. Implementations may clone the template method when + * present; completed-CD projection passes {@code null} when no Java template owns the member. + */ + default void addMethod( + ASTTypeDeclaration targetType, + ASTMethodDeclaration templateMethod, + String newName, + List paramTypes, + List paramNames, + String returnType, + boolean isStatic, + MethodBodySpec methodBody) { + throw unsupported("addMethod"); + } + + /** + * Create a new top-level type by cloning the provided template type and giving it the provided name. + */ + default void addType(ASTTypeDeclaration templateType, String newName) { + throw unsupported("addType"); + } + + /** Adds a completed-CD superclass or interface relationship to an existing Java type. */ + default void addSuperType( + ASTTypeDeclaration targetType, String superTypeName, boolean interfaceType) { + throw unsupported("addSuperType"); + } + + /** Sets whether a generated or adapted Java type is abstract. */ + default void setTypeAbstract(ASTTypeDeclaration targetType, boolean isAbstract) { + throw unsupported("setTypeAbstract"); + } + + /** Adds an enum constant introduced by completed-CD projection. */ + default void addEnumConstant( + ASTTypeDeclaration targetType, String constantName, int expectedIndex) { + throw unsupported("addEnumConstant"); + } + + /** + * Remove a field from the given target type (by template AST field reference). + */ + default void removeField(ASTTypeDeclaration targetType, ASTFieldDeclaration field) { + throw unsupported("removeField"); + } + + /** + * Remove a method from the given target type (by template AST method reference). + */ + default void removeMethod(ASTTypeDeclaration targetType, ASTMethodDeclaration method) { + throw unsupported("removeMethod"); + } + + private UnsupportedOperationException unsupported(String operation) { + return new UnsupportedOperationException( + getClass().getName() + " does not support updater operation: " + operation); + } + + /** + * Immutable description of the small generated method-body forms supported by the updater. + * + *

For example, {@code assignFieldAndReturnThis("name", "value")} represents {@code this.name = + * value; return this;}, while {@code returnNew("Person", List.of("name", "age"))} represents + * {@code return new Person(name, age);}. + */ + final class MethodBodySpec { + /** Supported generated method-body shapes. */ + public enum Kind { + /** Preserve a cloned body or synthesize a safe empty/default body. */ + EMPTY, + /** Replace a cloned implementation with a compilable default body. */ + SAFE_DEFAULT, + /** Preserve an implementation or synthesize a public, safe interface-contract body. */ + INTERFACE_CONTRACT, + /** Assign one parameter to a field and return {@code this}. */ + ASSIGN_FIELD_AND_RETURN_THIS, + /** Return a newly constructed value using selected fields as arguments. */ + RETURN_NEW + } + + private final Kind kind; + private final String fieldName; + private final String parameterName; + private final String constructorType; + private final java.util.List constructorFieldArguments; + + private MethodBodySpec( + Kind kind, + String fieldName, + String parameterName, + String constructorType, + List constructorFieldArguments) { + this.kind = kind; + this.fieldName = fieldName; + this.parameterName = parameterName; + this.constructorType = constructorType; + this.constructorFieldArguments = + constructorFieldArguments == null + ? java.util.List.of() + : java.util.List.copyOf(constructorFieldArguments); + } + + /** Returns a specification that requests no structured replacement body. */ + public static MethodBodySpec empty() { + return new MethodBodySpec(Kind.EMPTY, null, null, null, java.util.List.of()); + } + + /** Returns a specification that discards a cloned body and uses Java default values. */ + public static MethodBodySpec safeDefault() { + return new MethodBodySpec(Kind.SAFE_DEFAULT, null, null, null, java.util.List.of()); + } + + /** Returns a specification for a concrete implementation of an interface contract. */ + public static MethodBodySpec interfaceContract() { + return new MethodBodySpec( + Kind.INTERFACE_CONTRACT, null, null, null, java.util.List.of()); + } + + /** Returns a builder-style field-assignment specification. */ + public static MethodBodySpec assignFieldAndReturnThis(String fieldName, String parameterName) { + return new MethodBodySpec( + Kind.ASSIGN_FIELD_AND_RETURN_THIS, fieldName, parameterName, null, java.util.List.of()); + } + + /** Returns a specification that constructs and returns the requested type. */ + public static MethodBodySpec returnNew( + String constructorType, java.util.List fieldArguments) { + return new MethodBodySpec(Kind.RETURN_NEW, null, null, constructorType, fieldArguments); + } + + public Kind kind() { + return kind; + } + + public String fieldName() { + return fieldName; + } + + public String parameterName() { + return parameterName; + } + + public String constructorType() { + return constructorType; + } + + public List constructorFieldArguments() { + return constructorFieldArguments; + } + } } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdaterMill.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdaterMill.java new file mode 100644 index 00000000..25837db8 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdaterMill.java @@ -0,0 +1,38 @@ +package de.monticore.codeAdaption.updater; + +import de.monticore.codeAdaption.updater.spoonUpdater.SpoonUpdater; +import java.util.Objects; +import java.util.function.Supplier; + +/** Owns the updater lifecycle for one isolated adaptation pass. */ +public final class CodeUpdaterMill { + + private static Supplier updaterProvider = SpoonUpdater::new; + private static CodeUpdater updater; + + private CodeUpdaterMill() {} + + /** Restores the default Spoon-backed updater provider and clears the current updater. */ + public static synchronized void init() { + init(SpoonUpdater::new); + } + + /** Configures an interchangeable updater provider and clears the current updater. */ + public static synchronized void init(Supplier provider) { + updaterProvider = Objects.requireNonNull(provider, "provider"); + updater = null; + } + + /** Returns the updater for the current isolated adaptation pass. */ + public static synchronized CodeUpdater getUpdater() { + if (updater == null) { + updater = Objects.requireNonNull(updaterProvider.get(), "updaterProvider.get()"); + } + return updater; + } + + /** Discards the current updater while retaining the configured provider. */ + public static synchronized void reset() { + updater = null; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/regexUpdater/RegexUpdater.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/regexUpdater/RegexUpdater.java index 5e4e4406..e0a03b35 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/regexUpdater/RegexUpdater.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/regexUpdater/RegexUpdater.java @@ -13,6 +13,8 @@ import java.nio.file.Path; import java.util.Set; +// Fixme: RegExUpdater needs to be repaired +@Deprecated() public class RegexUpdater implements CodeUpdater { protected Set code; @@ -46,6 +48,12 @@ public void updateField( updateElement(srcName, newName); } + @Override + public void updateAssociationRole( + ASTTypeDeclaration srcType, String sourceRole, String concreteRole) { + updateElement(sourceRole, concreteRole); + } + @Override public void updateLocalVariable( ASTTypeDeclaration srcType, diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/ExecutableRewriteRegistry.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/ExecutableRewriteRegistry.java new file mode 100644 index 00000000..08571a4f --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/ExecutableRewriteRegistry.java @@ -0,0 +1,90 @@ +package de.monticore.codeAdaption.updater.spoonUpdater; + +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** Stores validated executable-signature and stable-key rewrite requests for one Spoon pass. */ +final class ExecutableRewriteRegistry { + private final Map> legacySignaturesByName = + new LinkedHashMap<>(); + private final Map rewritesByReference = new LinkedHashMap<>(); + + void clear() { + legacySignaturesByName.clear(); + rewritesByReference.clear(); + } + + void registerConcreteSignature(String methodName, List parameterTypes) { + ConcreteMethodSignature signature = + ConcreteMethodSignature.create(methodName, parameterTypes); + legacySignaturesByName + .computeIfAbsent(signature.methodName(), ignored -> new LinkedHashSet<>()) + .add(signature); + } + + void registerRewrite(StableElementKey reference, StableElementKey concrete) { + MethodRewrite rewrite = new MethodRewrite(reference, concrete); + rewritesByReference.put(rewrite.reference(), rewrite); + } + + boolean isEmpty() { + return legacySignaturesByName.isEmpty() && rewritesByReference.isEmpty(); + } + + boolean hasRewrites() { + return !rewritesByReference.isEmpty(); + } + + Collection rewrites() { + return List.copyOf(rewritesByReference.values()); + } + + List unambiguousLegacyParameters(String methodName) { + Set signatures = legacySignaturesByName.get(methodName); + return signatures == null || signatures.size() != 1 + ? null + : signatures.iterator().next().parameterTypes(); + } + + long concreteTargetsNamed(String methodName) { + return rewritesByReference.values().stream() + .map(MethodRewrite::concrete) + .filter(key -> methodName.equals(key.getName())) + .count(); + } + + /** Normalized legacy method signature registered without owner identity. */ + record ConcreteMethodSignature(String methodName, List parameterTypes) { + ConcreteMethodSignature { + if (methodName == null || methodName.isBlank()) { + throw new IllegalArgumentException("Method name must not be blank"); + } + if (parameterTypes == null) { + throw new IllegalArgumentException("Parameter types must not be null"); + } + parameterTypes = parameterTypes.stream().map(JavaSourceNames::normalizeType).toList(); + } + + static ConcreteMethodSignature create(String methodName, List parameterTypes) { + return new ConcreteMethodSignature(methodName, parameterTypes); + } + } + + /** Owner- and signature-aware mapping from a reference method to its concrete target. */ + record MethodRewrite(StableElementKey reference, StableElementKey concrete) { + MethodRewrite { + if (reference == null + || concrete == null + || reference.getKind() != StableElementKey.Kind.METHOD + || concrete.getKind() != StableElementKey.Kind.METHOD) { + throw new IllegalArgumentException("Method rewrites require two method keys"); + } + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonElementResolver.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonElementResolver.java new file mode 100644 index 00000000..44655c30 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonElementResolver.java @@ -0,0 +1,230 @@ +package de.monticore.codeAdaption.updater.spoonUpdater; + +import static de.monticore.codeAdaption.utils.JavaLoader.print; + +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; +import spoon.reflect.CtModel; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; + +final class SpoonElementResolver { + + private final Supplier model; + private final Map> typeMap = new LinkedHashMap<>(); + private final Map> methodMap = new LinkedHashMap<>(); + + SpoonElementResolver(Supplier model) { + this.model = model; + } + + void reset() { + typeMap.clear(); + methodMap.clear(); + } + + CtType getSpoonType(ASTTypeDeclaration mcType) { + if (typeMap.containsKey(mcType)) { + return typeMap.get(mcType); + } + CtModel currentModel = model.get(); + if (currentModel == null) { + throw new IllegalStateException("Cannot resolve a type before a Spoon model has been loaded"); + } + List> candidates = + currentModel.getAllTypes().stream() + .filter(candidate -> mcType.getName().equals(candidate.getSimpleName())) + .toList(); + CtType type = resolveTypeBySource(mcType, candidates); + typeMap.put(mcType, type); + return type; + } + + CtMethod getSpoonMethod(ASTTypeDeclaration mcType, ASTMethodDeclaration mcMethod) { + return findSpoonMethod(mcType, mcMethod) + .orElseThrow( + () -> + new IllegalStateException( + "No Spoon method corresponds to '" + + mcMethod.getName() + + "' in type '" + + mcType.getName() + + "'")); + } + + Optional> findSpoonMethod( + ASTTypeDeclaration mcType, ASTMethodDeclaration mcMethod) { + if (methodMap.containsKey(mcMethod)) { + return Optional.of(methodMap.get(mcMethod)); + } + + CtType spoonType = getSpoonType(mcType); + List> candidates = + spoonType.getMethods().stream() + .filter(candidate -> compare(mcMethod, candidate)) + .toList(); + Optional> method = + candidates.isEmpty() + ? Optional.empty() + : Optional.of( + requireUnique( + candidates, + "declared Spoon method '" + + mcMethod.getName() + + "' in '" + + spoonType.getQualifiedName() + + "'")); + method.ifPresent(value -> methodMap.put(mcMethod, value)); + return method; + } + + void cacheType(ASTTypeDeclaration mcType, CtType spoonType) { + typeMap.put(mcType, spoonType); + } + + boolean compare(ASTTypeDeclaration type, CtType spoonType) { + if (!type.getName().equals(spoonType.getSimpleName())) { + return false; + } + Optional expectedFile = sourceFile(type); + if (expectedFile.isEmpty()) { + return true; + } + return spoonSourceFile(spoonType) + .map( + actual -> + actual.equals(expectedFile.get()) + || commonTrailingSegments(actual, expectedFile.get()) >= 2) + .orElse(false); + } + + boolean compare(ASTMethodDeclaration mcMethod, CtMethod spoonMethod) { + if (!mcMethod.getName().equals(spoonMethod.getSimpleName())) { + return false; + } + if (!mcMethod.getFormalParameters().isPresentFormalParameterListing()) { + return spoonMethod.getParameters().isEmpty(); + } + List mcParams = + mcMethod.getFormalParameters().getFormalParameterListing().getFormalParameterList(); + if (spoonMethod.getParameters().size() != mcParams.size()) { + return false; + } + for (int i = 0; i < spoonMethod.getParameters().size(); i++) { + String expected = JavaSourceNames.normalizeType(print(mcParams.get(i).getMCType())); + String actual = normalizedSpoonType(spoonMethod.getParameters().get(i).getType()); + if (!expected.equals(actual)) { + return false; + } + } + + return true; + } + + private static String normalizedSpoonType(spoon.reflect.reference.CtTypeReference type) { + if (type == null) { + return "Object"; + } + return JavaSourceNames.normalizeType(type.toString()); + } + + private static Optional sourceFile(ASTTypeDeclaration type) { + return type.get_SourcePositionStart().getFileName().flatMap(SpoonElementResolver::pathOf); + } + + private static CtType resolveTypeBySource( + ASTTypeDeclaration mcType, List> candidates) { + if (candidates.isEmpty()) { + throw new IllegalStateException( + "No Spoon type corresponds to JavaDSL type '" + mcType.getName() + "'"); + } + Optional expected = sourceFile(mcType); + if (expected.isPresent()) { + List> exact = + candidates.stream() + .filter( + candidate -> + spoonSourceFile(candidate).map(expected.get()::equals).orElse(false)) + .toList(); + if (!exact.isEmpty()) { + return requireUnique(exact, "exact source match for '" + mcType.getName() + "'"); + } + + int greatestSuffix = + candidates.stream() + .map(SpoonElementResolver::spoonSourceFile) + .flatMap(Optional::stream) + .mapToInt(actual -> commonTrailingSegments(actual, expected.get())) + .max() + .orElse(0); + if (greatestSuffix >= 2) { + List> suffixMatches = + candidates.stream() + .filter( + candidate -> + spoonSourceFile(candidate) + .map(actual -> commonTrailingSegments(actual, expected.get())) + .orElse(0) + == greatestSuffix) + .toList(); + return requireUnique( + suffixMatches, + "best source-suffix match for '" + mcType.getName() + "' from " + expected.get()); + } + } + return requireUnique( + candidates, + "globally unique Spoon type named '" + + mcType.getName() + + "' (source " + + expected.map(Path::toString).orElse("unknown") + + ")"); + } + + private static Optional spoonSourceFile(CtType type) { + if (type.getPosition() == null || !type.getPosition().isValidPosition()) { + return Optional.empty(); + } + return Optional.of(type.getPosition().getFile().toPath().toAbsolutePath().normalize()); + } + + private static int commonTrailingSegments(Path first, Path second) { + int common = 0; + int firstIndex = first.getNameCount() - 1; + int secondIndex = second.getNameCount() - 1; + while (firstIndex >= 0 + && secondIndex >= 0 + && first.getName(firstIndex).toString().equals(second.getName(secondIndex).toString())) { + common++; + firstIndex--; + secondIndex--; + } + return common; + } + + private static Optional pathOf(String fileName) { + try { + return Optional.of(Path.of(fileName).toAbsolutePath().normalize()); + } catch (InvalidPathException ignored) { + return Optional.empty(); + } + } + + private static T requireUnique(List candidates, String description) { + int candidateCount = candidates.size(); + if (candidateCount != 1) { + throw new IllegalStateException( + "Expected exactly one " + description + " but found " + candidateCount); + } + return candidates.get(0); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonExecutableRepairService.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonExecutableRepairService.java new file mode 100644 index 00000000..815f9efa --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonExecutableRepairService.java @@ -0,0 +1,445 @@ +package de.monticore.codeAdaption.updater.spoonUpdater; + +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import spoon.reflect.code.CtExpression; +import spoon.reflect.code.CtInvocation; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtParameter; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.ModifierKind; +import spoon.reflect.reference.CtTypeReference; +import spoon.reflect.visitor.filter.TypeFilter; + +/** + * Repairs executable references and signatures after declaration and type transformations. + * + *

This service runs after grouping and declaration rewrites. It resolves overloads by stable + * owner/signature keys and uses guarded no-classpath fallbacks where Spoon cannot resolve a + * declaration. + */ +final class SpoonExecutableRepairService { + private final SpoonWorkspace workspace; + private final SpoonElementResolver resolver; + private final ExecutableRewriteRegistry rewriteRegistry = new ExecutableRewriteRegistry(); + + /** Creates an executable repair phase over the currently loaded Spoon workspace. */ + SpoonExecutableRepairService(SpoonWorkspace workspace, SpoonElementResolver resolver) { + this.workspace = workspace; + this.resolver = resolver; + } + + /** Clears all method signatures and stable-key rewrites registered for the previous pass. */ + void reset() { + rewriteRegistry.clear(); + } + + /** + * Registers an owner-independent concrete signature used by legacy update calls. Duplicate + * normalized signatures are collapsed by the registry. + */ + void registerConcreteMethodSignature(String methodName, List parameterTypes) { + if (methodName != null && !methodName.isBlank() && parameterTypes != null) { + rewriteRegistry.registerConcreteSignature(methodName, parameterTypes); + } + } + + /** Registers an owner- and signature-aware reference-method to concrete-method rewrite. */ + void registerMethodRewrite(StableElementKey reference, StableElementKey concrete) { + rewriteRegistry.registerRewrite(reference, concrete); + } + + /** + * Resolves a source method to its Spoon declaration and captures only the invocations that target + * that declaration. Capturing happens before the declaration is renamed so unresolved invocation + * names can be updated afterward without affecting unrelated overloads. + */ + MethodRename planMethodRename( + ASTTypeDeclaration sourceType, ASTMethodDeclaration sourceMethod) { + CtMethod target = resolver.getSpoonMethod(sourceType, sourceMethod); + String oldName = target.getSimpleName(); + CtType owner = target.getDeclaringType(); + List> invocations = new ArrayList<>(); + for (CtInvocation invocation : + workspace.model().getElements(new TypeFilter<>(CtInvocation.class))) { + if (invocation.getExecutable() != null + && oldName.equals(invocation.getExecutable().getSimpleName()) + && invokesMethodOn(invocation, target, owner)) { + invocations.add(invocation); + } + } + return new MethodRename(target, List.copyOf(invocations)); + } + + /** Applies a planned new name to the captured invocation executable references. */ + void renameInvocations(MethodRename rename, String newName) { + rename.invocations().forEach(invocation -> invocation.getExecutable().setSimpleName(newName)); + } + + /** + * Performs the final executable repair phase before printing: concrete invocation signatures are + * applied first, then illegal bodies are removed from abstract interface methods. + */ + void prepareForPrint(Map groupingMappings) { + applyConcreteMethodSignatures(groupingMappings); + enforceInterfaceMethodBodies(); + } + + /** + * Tests whether an invocation targets a selected method using, in order, resolved declaration + * identity, executable declaring-type identity, and a lexical owner/superclass fallback for + * Spoon's no-classpath mode. + */ + private boolean invokesMethodOn( + CtInvocation invocation, CtMethod target, CtType owner) { + try { + var declaration = invocation.getExecutable().getDeclaration(); + if (declaration != null) { + return declaration == target; + } + } catch (RuntimeException ignored) { + // Continue with type identity in no-classpath mode. + } + try { + CtTypeReference declaringType = invocation.getExecutable().getDeclaringType(); + if (declaringType != null && owner != null) { + return sameTypeName(declaringType.getQualifiedName(), owner.getQualifiedName()); + } + } catch (RuntimeException ignored) { + // Unresolved inherited calls are handled by the lexical owner fallback below. + } + CtType lexicalOwner = invocation.getParent(CtType.class); + if (lexicalOwner == null || owner == null) { + return false; + } + if (sameTypeName(lexicalOwner.getQualifiedName(), owner.getQualifiedName())) { + return true; + } + CtTypeReference superclass = lexicalOwner.getSuperclass(); + return superclass != null + && sameTypeName(superclass.getQualifiedName(), owner.getQualifiedName()); + } + + /** + * Reconciles every invocation with its registered concrete method signature. It renames resolved + * targets and adds missing arguments, but rejects calls that already supply too many arguments. + */ + private void applyConcreteMethodSignatures(Map groupingMappings) { + if (rewriteRegistry.isEmpty()) { + return; + } + for (CtInvocation invocation : + workspace.model().getElements(new TypeFilter<>(CtInvocation.class))) { + String methodName = + invocation.getExecutable() == null ? null : invocation.getExecutable().getSimpleName(); + StableElementKey target = + findConcreteRewriteTarget(invocation, methodName, groupingMappings); + List parameterTypes = + target == null + ? unambiguousLegacyParameters(methodName) + : target.getParameterTypeSources(); + if (parameterTypes == null) { + continue; + } + if (target != null && invocation.getExecutable() != null) { + invocation.getExecutable().setSimpleName(target.getName()); + } + if (invocation.getArguments().size() > parameterTypes.size()) { + throw new IllegalStateException( + "Concrete method '" + methodName + "' has fewer parameters than " + invocation); + } + for (int index = invocation.getArguments().size(); index < parameterTypes.size(); index++) { + invocation.addArgument(missingArgument(invocation, parameterTypes.get(index))); + } + } + } + + /** + * Supplies a missing concrete argument from the unique compatible enclosing parameter, or uses + * the Java default value when no unique parameter is available. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private CtExpression missingArgument(CtInvocation invocation, String parameterType) { + CtMethod enclosingMethod = invocation.getParent(CtMethod.class); + if (enclosingMethod != null) { + CtTypeReference expected = expectedTypeReference(enclosingMethod, parameterType); + List> exact = + enclosingMethod.getParameters().stream() + .filter(parameter -> parameter.getType() != null) + .filter( + parameter -> + sameArgumentType(parameter.getType(), expected, parameterType)) + .toList(); + if (exact.size() == 1) { + return workspace.factory().Code().createVariableRead(exact.get(0).getReference(), false); + } + if (exact.isEmpty()) { + List> compatibleSubtypes = + enclosingMethod.getParameters().stream() + .filter(parameter -> isSubtype(parameter.getType(), expected)) + .toList(); + if (compatibleSubtypes.size() == 1) { + return workspace + .factory() + .Code() + .createVariableRead(compatibleSubtypes.get(0).getReference(), false); + } + } + } + return workspace.defaultExpression(parameterType); + } + + private CtTypeReference expectedTypeReference( + CtMethod enclosingMethod, String parameterType) { + if (parameterType != null && parameterType.contains(".")) { + Optional> qualifiedMatch = + workspace.model().getAllTypes().stream() + .filter(type -> parameterType.equals(type.getQualifiedName())) + .findFirst(); + if (qualifiedMatch.isPresent()) { + return qualifiedMatch.get().getReference(); + } + } + if (parameterType != null && !parameterType.contains(".")) { + String simpleName = JavaSourceNames.simpleName(parameterType); + List> modelMatches = + workspace.model().getAllTypes().stream() + .filter(type -> simpleName.equals(type.getSimpleName())) + .toList(); + if (modelMatches.size() == 1) { + return modelMatches.get(0).getReference(); + } + CtType owner = enclosingMethod.getParent(CtType.class); + if (owner != null && owner.getPackage() != null) { + String localName = owner.getPackage().getQualifiedName() + "." + simpleName; + Optional> localMatch = + modelMatches.stream() + .filter(type -> localName.equals(type.getQualifiedName())) + .findFirst(); + if (localMatch.isPresent()) { + return localMatch.get().getReference(); + } + } + } + return workspace.createTypeReference(parameterType); + } + + private boolean isSubtype(CtTypeReference actual, CtTypeReference expected) { + if (actual == null || expected == null || actual.isPrimitive() || expected.isPrimitive()) { + return false; + } + String actualName = resolvedQualifiedName(actual); + String expectedName = resolvedQualifiedName(expected); + if (expectedName.contains(".") && !actualName.contains(".")) { + return false; + } + if (actualName.contains(".") + && expectedName.contains(".") + && !actualName.equals(expectedName) + && actual.getSimpleName().equals(expected.getSimpleName())) { + return false; + } + try { + return actual.isSubtypeOf(expected); + } catch (RuntimeException ignored) { + return false; + } + } + + /** Does not equate distinct known qualified types that merely share a simple name. */ + private static boolean sameArgumentType( + CtTypeReference actual, CtTypeReference expected, String expectedSource) { + if (actual == null || expected == null) { + return false; + } + String actualName = resolvedQualifiedName(actual); + String expectedName = resolvedQualifiedName(expected); + if (expectedSource != null && expectedSource.contains(".")) { + return actualName.equals(expectedName) + && sameNormalizedTypeShape(actual, expected); + } + return sameNormalizedTypeShape(actual, expected); + } + + /** Compares complete type shapes while intentionally ignoring package qualification. */ + private static boolean sameNormalizedTypeShape( + CtTypeReference actual, CtTypeReference expected) { + return JavaSourceNames.normalizeType(actual.toString()) + .equals(JavaSourceNames.normalizeType(expected.toString())); + } + + private static String resolvedQualifiedName(CtTypeReference type) { + try { + CtType declaration = type.getTypeDeclaration(); + if (declaration != null && declaration.getQualifiedName() != null) { + return declaration.getQualifiedName(); + } + } catch (RuntimeException ignored) { + // Fall back to the reference's own no-classpath name. + } + String qualifiedName = type.getQualifiedName(); + return qualifiedName == null ? type.getSimpleName() : qualifiedName; + } + + /** + * Selects the unique stable-key rewrite matching invocation name, owner, and argument types. + * Null-literal argument types act as wildcards because Spoon cannot infer their target type. + */ + private StableElementKey findConcreteRewriteTarget( + CtInvocation invocation, + String methodName, + Map groupingMappings) { + if (methodName == null || !rewriteRegistry.hasRewrites()) { + return null; + } + String owner = ownerName(invocation); + List invocationTypes = invocationArgumentTypes(invocation); + List matches = new ArrayList<>(); + for (ExecutableRewriteRegistry.MethodRewrite rewrite : rewriteRegistry.rewrites()) { + StableElementKey reference = rewrite.reference(); + StableElementKey concrete = rewrite.concrete(); + if ((!methodName.equals(reference.getName()) && !methodName.equals(concrete.getName())) + || !ownerMatches(owner, reference, concrete, groupingMappings)) { + continue; + } + if (!signatureMatches(reference.getParameterTypes(), invocationTypes)) { + continue; + } + matches.add(concrete); + } + if (matches.size() == 1) { + return matches.get(0); + } + if (matches.size() > 1) { + throw new IllegalStateException( + "Ambiguous method rewrite for '" + + methodName + + "' on owner '" + + owner + + "' with arguments " + + invocationTypes); + } + return null; + } + + /** Returns whether an invocation owner matches the reference, concrete, or grouping owner. */ + private static boolean ownerMatches( + String owner, + StableElementKey reference, + StableElementKey concrete, + Map groupingMappings) { + if (owner == null + || (reference.getOwnerType().isEmpty() && concrete.getOwnerType().isEmpty())) { + return true; + } + String referenceOwner = reference.getOwnerType().orElse(null); + String concreteOwner = concrete.getOwnerType().orElse(null); + String groupedOwner = groupingMappings.get(concreteOwner); + return sameTypeName(owner, referenceOwner) + || sameTypeName(owner, concreteOwner) + || sameTypeName(owner, groupedOwner); + } + + /** Compares normalized parameter types, treating unknown actual argument types as compatible. */ + private static boolean signatureMatches(List expected, List actual) { + if (expected.size() != actual.size()) { + return false; + } + for (int index = 0; index < expected.size(); index++) { + String actualType = actual.get(index); + if (actualType != null + && !sameTypeName(JavaSourceNames.normalizeType(expected.get(index)), actualType)) { + return false; + } + } + return true; + } + + /** + * Returns normalized invocation argument types; unresolved and Spoon {@code } values + * are represented as {@code null}. + */ + private static List invocationArgumentTypes(CtInvocation invocation) { + List result = new ArrayList<>(); + for (CtExpression argument : invocation.getArguments()) { + CtTypeReference type = argument.getType(); + String qualifiedName = type == null ? null : type.getQualifiedName(); + // Spoon represents null literals as the synthetic type "". + result.add( + qualifiedName == null || qualifiedName.isBlank() || qualifiedName.startsWith("<") + ? null + : JavaSourceNames.normalizeType(qualifiedName)); + } + return result; + } + + /** + * Returns legacy parameters only when one signature and at most one concrete target use the + * method name. + */ + private List unambiguousLegacyParameters(String methodName) { + List parameters = rewriteRegistry.unambiguousLegacyParameters(methodName); + if (parameters == null) { + return null; + } + return rewriteRegistry.concreteTargetsNamed(methodName) <= 1 ? parameters : null; + } + + /** + * Resolves an invocation owner from its executable, its explicit target, or finally the lexical + * enclosing type. + */ + private static String ownerName(CtInvocation invocation) { + try { + if (invocation.getExecutable() != null + && invocation.getExecutable().getDeclaringType() != null) { + return invocation.getExecutable().getDeclaringType().getQualifiedName(); + } + } catch (RuntimeException ignored) { + // Spoon may not resolve declaring types in no-classpath mode. + } + try { + if (invocation.getTarget() != null && invocation.getTarget().getType() != null) { + return invocation.getTarget().getType().getQualifiedName(); + } + } catch (RuntimeException ignored) { + // Fall through to the lexical owner. + } + CtType parent = invocation.getParent(CtType.class); + return parent == null ? null : parent.getQualifiedName(); + } + + /** Removes bodies from non-default, non-static, non-private interface methods. */ + private void enforceInterfaceMethodBodies() { + for (CtType type : workspace.model().getAllTypes()) { + if (!type.isInterface()) { + continue; + } + for (CtMethod method : type.getMethods()) { + if (!method.isDefaultMethod() + && !method.hasModifier(ModifierKind.STATIC) + && !method.hasModifier(ModifierKind.PRIVATE)) { + method.setBody(null); + } + } + } + } + + /** Compares qualified names when available and otherwise accepts equal simple type names. */ + private static boolean sameTypeName(String first, String second) { + if (first == null || second == null) { + return false; + } + return first.equals(second) + || JavaSourceNames.simpleName(first).equals(JavaSourceNames.simpleName(second)); + } + + /** Method declaration and invocations resolved to it before the rename. */ + record MethodRename(CtMethod target, List> invocations) {} +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonGenerationService.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonGenerationService.java new file mode 100644 index 00000000..cb2cecbf --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonGenerationService.java @@ -0,0 +1,554 @@ +package de.monticore.codeAdaption.updater.spoonUpdater; + +import de.monticore.codeAdaption.updater.CodeUpdater.MethodBodySpec; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import spoon.reflect.code.CtAssignment; +import spoon.reflect.code.CtBlock; +import spoon.reflect.code.CtConstructorCall; +import spoon.reflect.code.CtExpression; +import spoon.reflect.code.CtLiteral; +import spoon.reflect.code.CtReturn; +import spoon.reflect.code.CtThisAccess; +import spoon.reflect.code.CtTypeAccess; +import spoon.reflect.code.CtVariableAccess; +import spoon.reflect.declaration.CtField; +import spoon.reflect.declaration.CtEnum; +import spoon.reflect.declaration.CtEnumValue; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtParameter; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.ModifierKind; +import spoon.reflect.reference.CtTypeReference; +import spoon.reflect.reference.CtParameterReference; +import spoon.reflect.reference.CtVariableReference; +import spoon.refactoring.Refactoring; + +/** + * Creates, clones, completes, and removes Spoon declarations and constructs supported method + * bodies. + * + *

It does not rename existing declarations or rewrite references; those mutations belong to + * {@link SpoonTransformationService}. + */ +final class SpoonGenerationService { + private final SpoonWorkspace workspace; + private final SpoonElementResolver resolver; + + SpoonGenerationService(SpoonWorkspace workspace, SpoonElementResolver resolver) { + this.workspace = workspace; + this.resolver = resolver; + } + + void addField( + ASTTypeDeclaration targetType, + ASTFieldDeclaration templateField, + String newName, + String newType, + boolean isStatic) { + requireName(newName, "Field name"); + requireName(newType, "Field type"); + CtType spoonType = resolver.getSpoonType(targetType); + CtField existingField = spoonType.getField(newName); + if (existingField != null) { + existingField.setType(workspace.createTypeReference(newType)); + setStatic(existingField, isStatic); + return; + } + String templateName = + templateField == null + ? null + : templateField.getVariableDeclarator(0).getDeclarator().getName(); + CtField sourceField = templateName == null ? null : spoonType.getField(templateName); + CtField clone = + sourceField == null ? workspace.factory().Core().createField() : sourceField.clone(); + clone.setSimpleName(newName); + clone.setType(workspace.createTypeReference(newType)); + setStatic(clone, isStatic); + spoonType.addField(clone); + } + + void addType(ASTTypeDeclaration templateType, String newName) { + requireName(newName, "Type name"); + CtType source = resolver.getSpoonType(templateType); + CtType existing = + source.getPackage() == null ? null : source.getPackage().getType(newName); + if (existing != null && existing != source) { + return; + } + // Every adaptation selection owns an isolated source tree. Transforming that run's template + // avoids leaking the unadapted template beside the generated type and eliminates merge + // collisions between otherwise independent incarnation runs. + Refactoring.changeTypeName(source, newName); + resolver.cacheType(templateType, source); + } + + void addSuperType( + ASTTypeDeclaration targetType, String superTypeName, boolean interfaceType) { + requireName(superTypeName, "Supertype name"); + CtType target = resolver.getSpoonType(targetType); + CtTypeReference reference = workspace.createTypeReference(superTypeName); + if (interfaceType || target.isInterface()) { + boolean present = + target.getSuperInterfaces().stream() + .anyMatch( + existing -> + JavaSourceNames.simpleName(existing.getQualifiedName()) + .equals(JavaSourceNames.simpleName(superTypeName))); + if (!present) { + target.addSuperInterface(reference); + } + } else { + target.setSuperclass(reference); + } + } + + /** Reconciles a generated Java class modifier with the authoritative target CD type. */ + void setTypeAbstract(ASTTypeDeclaration targetType, boolean isAbstract) { + CtType target = resolver.getSpoonType(targetType); + if (target.isInterface()) { + return; + } + if (isAbstract) { + target.addModifier(ModifierKind.ABSTRACT); + } else { + target.removeModifier(ModifierKind.ABSTRACT); + } + } + + void addEnumConstant( + ASTTypeDeclaration targetType, String constantName, int expectedIndex) { + requireName(constantName, "Enum constant name"); + CtType target = resolver.getSpoonType(targetType); + if (!(target instanceof CtEnum enumType)) { + throw new IllegalStateException(target.getQualifiedName() + " is not an enum"); + } + boolean present = + enumType.getEnumValues().stream() + .anyMatch(value -> constantName.equals(value.getSimpleName())); + if (!present) { + CtEnumValue value = workspace.factory().Core().createEnumValue(); + value.setSimpleName(constantName); + List> values = new ArrayList<>(enumType.getEnumValues()); + values.add(Math.min(Math.max(expectedIndex, 0), values.size()), value); + enumType.setEnumValues(values); + } + } + + void addMethod( + ASTTypeDeclaration targetType, + ASTMethodDeclaration templateMethod, + String newName, + List parameterTypes, + List parameterNames, + String returnType, + boolean isStatic, + MethodBodySpec methodBody) { + validateMethodInput(newName, parameterTypes, parameterNames); + Objects.requireNonNull(methodBody, "Method body specification must not be null"); + if (methodBody.kind() == MethodBodySpec.Kind.INTERFACE_CONTRACT && isStatic) { + throw new IllegalStateException("An interface contract implementation cannot be static"); + } + CtType spoonType = resolver.getSpoonType(targetType); + CtMethod existingMethod = findMethod(spoonType, newName, parameterTypes); + if (existingMethod != null) { + if (methodBody.kind() == MethodBodySpec.Kind.INTERFACE_CONTRACT) { + completeExistingInterfaceContract(existingMethod, returnType); + return; + } + existingMethod.setType(workspace.createTypeReference(returnType)); + setStatic(existingMethod, isStatic); + return; + } + if (methodBody.kind() == MethodBodySpec.Kind.INTERFACE_CONTRACT + && hasInheritedInterfaceImplementation( + spoonType, newName, parameterTypes, returnType)) { + return; + } + CtMethod clone = + cloneConfiguredMethod( + targetType, + templateMethod, + newName, + parameterTypes, + parameterNames, + returnType, + hasReplacementBody(methodBody)); + setStatic(clone, isStatic); + if (methodBody.kind() == MethodBodySpec.Kind.INTERFACE_CONTRACT) { + clone.addModifier(ModifierKind.PUBLIC); + clone.removeModifier(ModifierKind.ABSTRACT); + } + applyMethodBodySpec(targetType, clone, methodBody); + spoonType.addMethod(clone); + } + + /** + * Turns an existing declaration into a legal concrete interface implementation without + * replacing a handwritten body. Signature conflicts are rejected before visibility/body repair. + */ + private void completeExistingInterfaceContract( + CtMethod existingMethod, String contractReturnType) { + if (existingMethod.hasModifier(ModifierKind.STATIC)) { + throw new IllegalStateException( + "Static method " + + existingMethod.getSignature() + + " cannot implement an interface contract"); + } + CtTypeReference existingReturn = existingMethod.getType(); + CtTypeReference contractReturn = workspace.createTypeReference(contractReturnType); + if (!isCompatibleInterfaceReturn(existingReturn, contractReturn)) { + throw new IllegalStateException( + "Method " + + existingMethod.getSignature() + + " returns " + + typeName(existingReturn) + + " but interface contract requires " + + typeName(contractReturn)); + } + existingMethod.removeModifier(ModifierKind.PRIVATE); + existingMethod.removeModifier(ModifierKind.PROTECTED); + existingMethod.addModifier(ModifierKind.PUBLIC); + existingMethod.removeModifier(ModifierKind.ABSTRACT); + if (existingMethod.getBody() == null) { + existingMethod.setBody(safeDefaultBody(typeName(existingReturn))); + } + } + + /** Accepts identical returns and Java covariance, but never mixes primitive and reference types. */ + private boolean isCompatibleInterfaceReturn( + CtTypeReference actualReturn, CtTypeReference expectedReturn) { + if (actualReturn == null || expectedReturn == null) { + return false; + } + if (sameType(actualReturn, expectedReturn)) { + return true; + } + if (isPrimitiveOrVoid(actualReturn) || isPrimitiveOrVoid(expectedReturn)) { + return false; + } + if ("Object".equals(expectedReturn.getSimpleName())) { + return true; + } + try { + return actualReturn.isSubtypeOf(expectedReturn); + } catch (RuntimeException ignored) { + return false; + } + } + + private boolean sameType(CtTypeReference first, CtTypeReference second) { + String firstQualified = first.getQualifiedName(); + String secondQualified = second.getQualifiedName(); + if (Objects.equals(firstQualified, secondQualified)) { + return true; + } + return first.getSimpleName().equals(second.getSimpleName()) + && (first.isSimplyQualified() || second.isSimplyQualified()); + } + + private boolean isPrimitiveOrVoid(CtTypeReference type) { + return type.isPrimitive() || "void".equals(type.getSimpleName()); + } + + private String typeName(CtTypeReference type) { + if (type == null) { + return "Object"; + } + String qualifiedName = type.getQualifiedName(); + return qualifiedName == null || qualifiedName.isBlank() ? type.getSimpleName() : qualifiedName; + } + + private boolean requiresSignatureOnlyMethod( + ASTTypeDeclaration targetType, ASTMethodDeclaration templateMethod) { + CtType target = resolver.getSpoonType(targetType); + if (target.isInterface()) { + return true; + } + if (templateMethod == null) { + return false; + } + return resolver + .findSpoonMethod(targetType, templateMethod) + .map(method -> method.hasModifier(ModifierKind.ABSTRACT)) + .orElse(false); + } + + void removeField(ASTTypeDeclaration targetType, ASTFieldDeclaration field) { + String name = field.getVariableDeclarator(0).getDeclarator().getName(); + CtField target = resolver.getSpoonType(targetType).getField(name); + if (target != null) { + target.delete(); + } + } + + void removeMethod(ASTTypeDeclaration targetType, ASTMethodDeclaration method) { + resolver.findSpoonMethod(targetType, method).ifPresent(CtMethod::delete); + } + + private CtMethod cloneConfiguredMethod( + ASTTypeDeclaration targetType, + ASTMethodDeclaration templateMethod, + String newName, + List parameterTypes, + List parameterNames, + String returnType, + boolean replacementBody) { + CtType target = resolver.getSpoonType(targetType); + CtMethod clone = + templateMethod == null + ? workspace.factory().Core().createMethod() + : resolver + .findSpoonMethod(targetType, templateMethod) + .map(CtMethod::clone) + .orElseGet(() -> workspace.factory().Core().createMethod()); + clone.setSimpleName(newName); + int sharedParameters = Math.min(clone.getParameters().size(), parameterNames.size()); + for (int index = 0; index < sharedParameters; index++) { + updateParameter( + clone, + clone.getParameters().get(index), + parameterNames.get(index), + parameterTypes.get(index)); + } + if (clone.getParameters().size() < parameterNames.size()) { + for (int index = clone.getParameters().size(); index < parameterNames.size(); index++) { + CtParameter parameter = workspace.factory().Core().createParameter(); + parameter.setSimpleName(parameterNames.get(index)); + parameter.setType(workspace.createTypeReference(parameterTypes.get(index))); + clone.addParameter(parameter); + } + } else { + while (clone.getParameters().size() > parameterNames.size()) { + clone.removeParameter(clone.getParameters().get(clone.getParameters().size() - 1)); + } + } + if (returnType != null && !returnType.isBlank()) { + clone.setType(workspace.createTypeReference(returnType)); + } + boolean primitiveBodyReturnsNull = + !replacementBody + && clone.getType() != null + && clone.getType().isPrimitive() + && clone.getElements(new spoon.reflect.visitor.filter.TypeFilter<>(CtReturn.class)) + .stream() + .map(CtReturn::getReturnedExpression) + .anyMatch( + expression -> + expression == null + || (expression instanceof CtLiteral literal + && literal.getValue() == null) + || "null".equals(expression.toString()) + || "".equals(expression.toString())); + if (requiresSignatureOnlyMethod(targetType, templateMethod)) { + clone.setBody(null); + if (!target.isInterface()) { + clone.addModifier(ModifierKind.ABSTRACT); + } + } else if (primitiveBodyReturnsNull) { + clone.setBody(safeDefaultBody(returnType)); + } else if (clone.getBody() == null && !"void".equals(returnType)) { + CtBlock body = workspace.factory().Core().createBlock(); + CtReturn returnStatement = workspace.factory().Core().createReturn(); + returnStatement.setReturnedExpression((CtExpression) workspace.defaultExpression(returnType)); + body.addStatement(returnStatement); + clone.setBody(body); + } else if (clone.getBody() == null) { + clone.setBody(workspace.factory().Core().createBlock()); + } + return clone; + } + + private void updateParameter( + CtMethod method, CtParameter parameter, String newName, String newType) { + String oldName = parameter.getSimpleName(); + if (!oldName.equals(newName)) { + for (CtVariableAccess access : + method.getElements( + new spoon.reflect.visitor.filter.TypeFilter<>(CtVariableAccess.class))) { + if (access.getVariable() == null) { + continue; + } + CtVariableReference reference = access.getVariable(); + if (reference.getDeclaration() == parameter + || (reference instanceof CtParameterReference + && reference.getDeclaration() == null + && oldName.equals(reference.getSimpleName()))) { + reference.setSimpleName(newName); + } + } + parameter.setSimpleName(newName); + } + parameter.setType(workspace.createTypeReference(newType)); + } + + private CtBlock safeDefaultBody(String returnType) { + CtBlock body = workspace.factory().Core().createBlock(); + if (returnType != null && !returnType.isBlank() && !"void".equals(returnType)) { + CtReturn returnStatement = workspace.factory().Core().createReturn(); + returnStatement.setReturnedExpression((CtExpression) workspace.defaultExpression(returnType)); + body.addStatement(returnStatement); + } + return body; + } + + private static boolean hasReplacementBody(MethodBodySpec methodBody) { + return methodBody.kind() != MethodBodySpec.Kind.EMPTY + && methodBody.kind() != MethodBodySpec.Kind.INTERFACE_CONTRACT; + } + + /** Checks inherited declarations without ever mutating the declaring supertype. */ + private boolean hasInheritedInterfaceImplementation( + CtType type, String name, List parameterTypes, String returnType) { + CtTypeReference expectedReturn = workspace.createTypeReference(returnType); + for (CtMethod method : type.getAllMethods()) { + if (method.getDeclaringType() == type || !matchesSignature(method, name, parameterTypes)) { + continue; + } + if (method.hasModifier(ModifierKind.PUBLIC) + && !method.hasModifier(ModifierKind.STATIC) + && !method.hasModifier(ModifierKind.ABSTRACT) + && isCompatibleInterfaceReturn(method.getType(), expectedReturn)) { + return true; + } + } + return false; + } + + private CtMethod findMethod(CtType type, String name, List parameterTypes) { + for (CtMethod method : type.getMethods()) { + if (matchesSignature(method, name, parameterTypes)) { + return method; + } + } + return null; + } + + private boolean matchesSignature( + CtMethod method, String name, List parameterTypes) { + if (!name.equals(method.getSimpleName()) + || method.getParameters().size() != parameterTypes.size()) { + return false; + } + for (int index = 0; index < parameterTypes.size(); index++) { + CtTypeReference actualType = method.getParameters().get(index).getType(); + CtTypeReference expectedType = workspace.createTypeReference(parameterTypes.get(index)); + if (!sameType(actualType, expectedType)) { + return false; + } + } + return true; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private void applyMethodBodySpec( + ASTTypeDeclaration targetType, CtMethod clone, MethodBodySpec methodBody) { + if (methodBody.kind() == MethodBodySpec.Kind.EMPTY + || methodBody.kind() == MethodBodySpec.Kind.INTERFACE_CONTRACT) { + return; + } + if (methodBody.kind() == MethodBodySpec.Kind.SAFE_DEFAULT) { + if (!clone.hasModifier(ModifierKind.ABSTRACT)) { + clone.setBody(safeDefaultBody(typeName(clone.getType()))); + } + return; + } + CtBlock body = workspace.factory().Core().createBlock(); + clone.setBody(body); + switch (methodBody.kind()) { + case ASSIGN_FIELD_AND_RETURN_THIS: + requireName(methodBody.fieldName(), "Assigned field name"); + requireName(methodBody.parameterName(), "Assigned parameter name"); + CtParameter parameter = + clone.getParameters().stream() + .filter(value -> value.getSimpleName().equals(methodBody.parameterName())) + .findFirst() + .orElseThrow( + () -> + new IllegalArgumentException( + "Generated body references missing parameter '" + + methodBody.parameterName() + + "'")); + CtAssignment assignment = workspace.factory().Core().createAssignment(); + assignment.setAssigned( + (CtExpression) + workspace + .factory() + .Code() + .createCodeSnippetExpression("this." + methodBody.fieldName())); + CtVariableReference variableReference = parameter.getReference(); + assignment.setAssignment( + (CtExpression) workspace.factory().Code().createVariableRead(variableReference, false)); + body.addStatement(assignment); + CtReturn setterReturn = workspace.factory().Core().createReturn(); + setterReturn.setReturnedExpression((CtExpression) createThisAccess(targetType)); + body.addStatement(setterReturn); + break; + case RETURN_NEW: + requireName(methodBody.constructorType(), "Constructor type"); + CtConstructorCall constructorCall = workspace.factory().Core().createConstructorCall(); + constructorCall.setType(workspace.createTypeReference(methodBody.constructorType())); + for (String fieldArgument : methodBody.constructorFieldArguments()) { + requireName(fieldArgument, "Constructor field argument"); + constructorCall.addArgument( + workspace.factory().Code().createCodeSnippetExpression("this." + fieldArgument)); + } + CtReturn buildReturn = workspace.factory().Core().createReturn(); + buildReturn.setReturnedExpression((CtExpression) constructorCall); + body.addStatement(buildReturn); + break; + default: + throw new IllegalArgumentException("Unsupported method body kind: " + methodBody.kind()); + } + } + + private CtThisAccess createThisAccess(ASTTypeDeclaration targetType) { + CtType target = resolver.getSpoonType(targetType); + CtThisAccess thisAccess = workspace.factory().Core().createThisAccess(); + CtTypeReference typeReference = + workspace.factory().Type().createReference(target.getSimpleName()); + try { + CtTypeAccess typeAccess = workspace.factory().Code().createTypeAccess(typeReference); + thisAccess.setTarget(typeAccess); + } catch (RuntimeException ignored) { + thisAccess.setType(typeReference); + } + return thisAccess; + } + + private static void validateMethodInput( + String methodName, List parameterTypes, List parameterNames) { + requireName(methodName, "Method name"); + Objects.requireNonNull(parameterTypes, "Parameter types must not be null"); + Objects.requireNonNull(parameterNames, "Parameter names must not be null"); + if (parameterTypes.size() != parameterNames.size()) { + throw new IllegalArgumentException( + "Parameter type/name count differs: " + + parameterTypes.size() + + " types and " + + parameterNames.size() + + " names"); + } + parameterTypes.forEach(type -> requireName(type, "Parameter type")); + parameterNames.forEach(name -> requireName(name, "Parameter name")); + } + + private static void requireName(String value, String description) { + if (value == null || value.isBlank()) { + throw new IllegalArgumentException(description + " must not be blank"); + } + } + + private static void setStatic(spoon.reflect.declaration.CtModifiable declaration, boolean value) { + if (value) { + declaration.addModifier(ModifierKind.STATIC); + } else { + declaration.removeModifier(ModifierKind.STATIC); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonTransformationService.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonTransformationService.java new file mode 100644 index 00000000..9ba4d474 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonTransformationService.java @@ -0,0 +1,463 @@ +package de.monticore.codeAdaption.updater.spoonUpdater; + +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.se_rwth.commons.logging.Log; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import spoon.refactoring.CtRenameGenericVariableRefactoring; +import spoon.refactoring.Refactoring; +import spoon.reflect.code.CtFieldAccess; +import spoon.reflect.code.CtLocalVariable; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtParameter; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtVariable; +import spoon.reflect.reference.CtTypeReference; +import spoon.reflect.visitor.filter.TypeFilter; + +/** + * Applies declaration, variable, grouping, and type-reference mutations to an already loaded Spoon + * model. + * + *

Creation/removal remains in {@link SpoonGenerationService}; executable overload and invocation + * repair remains in {@link SpoonExecutableRepairService}. Keeping these phases separate avoids one + * stateful catch-all service and makes their ordering explicit. + */ +final class SpoonTransformationService { + private final SpoonWorkspace workspace; + private final SpoonElementResolver resolver; + private final SpoonExecutableRepairService executableRepairs; + private Map groupingMappings = Collections.emptyMap(); + private Map>> typeReferencesBySimpleName; + private Map> typeDeclarationsBySimpleName; + + SpoonTransformationService( + SpoonWorkspace workspace, + SpoonElementResolver resolver, + SpoonExecutableRepairService executableRepairs) { + this.workspace = workspace; + this.resolver = resolver; + this.executableRepairs = executableRepairs; + } + + void reset() { + groupingMappings = Collections.emptyMap(); + typeReferencesBySimpleName = null; + typeDeclarationsBySimpleName = null; + } + + /** + * Sets incarnation-name to grouping-type-name replacements for this isolated Spoon pass. + * Qualified keys target only that qualified incarnation; simple keys are applied only when the + * loaded model contains one unambiguous declaration with that simple name. + */ + void setGroupingMappings(Map mappings) { + groupingMappings = + mappings == null || mappings.isEmpty() + ? Collections.emptyMap() + : new LinkedHashMap<>(mappings); + } + + void prepareForPrint() { + applyGroupingToModel(); + executableRepairs.prepareForPrint(groupingMappings); + } + + void updateType(ASTTypeDeclaration source, String newName) { + CtType target = resolver.getSpoonType(source); + if (!target.getSimpleName().equals(newName)) { + Refactoring.changeTypeName(target, newName); + } + } + + void updateMethod( + ASTTypeDeclaration sourceType, ASTMethodDeclaration sourceMethod, String newName) { + SpoonExecutableRepairService.MethodRename rename = + executableRepairs.planMethodRename(sourceType, sourceMethod); + Refactoring.changeMethodName(rename.target(), newName); + executableRepairs.renameInvocations(rename, newName); + } + + void updateField(ASTTypeDeclaration sourceType, ASTFieldDeclaration sourceField, String newName) { + String sourceName = sourceField.getVariableDeclarator(0).getDeclarator().getName(); + CtVariable field = resolver.getSpoonType(sourceType).getField(sourceName); + if (field == null) { + Log.warn( + "Cannot rename field '" + + sourceName + + "' in " + + sourceType.getName() + + " because no Spoon target exists; completed-member projection may add it later."); + return; + } + renameVariable(field, newName); + } + + void updateAssociationRole( + ASTTypeDeclaration sourceType, String sourceRole, String concreteRole) { + if (sourceRole == null || concreteRole == null || sourceRole.equals(concreteRole)) { + return; + } + CtType owner = resolver.getSpoonType(sourceType); + for (CtFieldAccess access : owner.getElements(new TypeFilter<>(CtFieldAccess.class))) { + if (access.getParent(CtType.class) == owner + && access.getVariable() != null + && sourceRole.equals(access.getVariable().getSimpleName())) { + access.getVariable().setSimpleName(concreteRole); + } + } + } + + void updateSuperType(ASTTypeDeclaration type, ASTMCType supertype, String newName) { + String sourceName = JavaLoader.print(supertype); + CtType spoonType = resolver.getSpoonType(type); + CtTypeReference superclass = spoonType.getSuperclass(); + if (superclass != null && superclass.getSimpleName().equals(sourceName)) { + rewriteTypeReferenceName(superclass, newName); + return; + } + for (CtTypeReference superInterface : spoonType.getSuperInterfaces()) { + if (superInterface.getSimpleName().equals(sourceName)) { + rewriteTypeReferenceName(superInterface, newName); + } + } + } + + void updateLocalVariable( + ASTTypeDeclaration sourceType, + ASTMethodDeclaration sourceMethod, + ASTLocalVariableDeclaration sourceVariable, + String newName) { + CtMethod method = resolver.getSpoonMethod(sourceType, sourceMethod); + String sourceName = sourceVariable.getVariableDeclarator(0).getDeclarator().getName(); + List> matches = method.getElements(Objects::nonNull); + matches.removeIf(variable -> !sourceName.equals(variable.getSimpleName())); + CtLocalVariable target = + selectByPosition(matches, sourceVariable.get_SourcePositionStart().getLine(), sourceName); + renameVariable(target, newName); + } + + void updateMethodParameter( + ASTTypeDeclaration sourceType, + ASTMethodDeclaration sourceMethod, + ASTFormalParameter sourceParameter, + String newName) { + CtMethod method = resolver.getSpoonMethod(sourceType, sourceMethod); + String sourceName = sourceParameter.getDeclarator().getName(); + List> parameters = + method.getParameters().stream() + .filter(parameter -> sourceName.equals(parameter.getSimpleName())) + .collect(Collectors.toList()); + if (!parameters.isEmpty()) { + renameVariable(selectUnique(parameters, sourceName), newName); + return; + } + List> locals = method.getElements(Objects::nonNull); + locals.removeIf(variable -> !sourceName.equals(variable.getSimpleName())); + CtLocalVariable target = + selectByPosition(locals, sourceParameter.get_SourcePositionStart().getLine(), sourceName); + renameVariable(target, newName); + } + + void updateCDType(ASTCDType type, String newName) { + indexTypeReferences(); + List> candidates = + typeReferencesBySimpleName.getOrDefault(type.getName(), List.of()); + if (candidates.isEmpty()) { + return; + } + Set modelDeclarations = + typeDeclarationsBySimpleName.getOrDefault(type.getName(), Set.of()); + if (modelDeclarations.size() > 1) { + throw new IllegalStateException( + "Ambiguous source type '" + + type.getName() + + "' is declared by multiple adapter types " + + modelDeclarations); + } + String modelIdentity = + modelDeclarations.isEmpty() ? null : modelDeclarations.iterator().next(); + String modelPackage = + modelIdentity == null || !modelIdentity.contains(".") + ? "" + : modelIdentity.substring(0, modelIdentity.lastIndexOf('.')); + List> selected = + candidates.stream() + .filter( + reference -> { + Optional identity = resolvedTypeIdentity(reference); + if (modelIdentity != null) { + if (identity.isPresent()) { + return modelIdentity.equals(identity.get()); + } + CtType owner = reference.getParent(CtType.class); + String ownerPackage = + owner == null || owner.getPackage() == null + ? "" + : owner.getPackage().getQualifiedName(); + return modelPackage.equals(ownerPackage); + } + if (identity.isEmpty()) { + return true; + } + // In no-classpath mode Spoon still gives unresolved same-package references a + // qualified name (for example Concrete.Role). Those are adapter identities and + // must be rewritten. A genuinely resolved foreign type such as java.util.Date + // has a different package and must remain untouched. + CtType owner = reference.getParent(CtType.class); + String ownerPackage = + owner == null || owner.getPackage() == null + ? "" + : owner.getPackage().getQualifiedName(); + String expectedIdentity = + ownerPackage.isEmpty() + ? type.getName() + : ownerPackage + "." + type.getName(); + return expectedIdentity.equals(identity.get()); + }) + .toList(); + if (selected.isEmpty()) { + return; + } + if (modelIdentity == null) { + Set ownerPackages = + selected.stream() + .map(reference -> reference.getParent(CtType.class)) + .filter(Objects::nonNull) + .map(owner -> owner.getPackage() == null ? "" : owner.getPackage().getQualifiedName()) + .collect(Collectors.toSet()); + if (ownerPackages.size() > 1) { + throw new IllegalStateException( + "Ambiguous unresolved type '" + + type.getName() + + "' occurs in multiple packages " + + ownerPackages); + } + } + for (CtTypeReference reference : selected) { + rewriteTypeReferenceName(reference, newName); + } + } + + private void indexTypeReferences() { + if (typeReferencesBySimpleName != null) { + return; + } + typeReferencesBySimpleName = new LinkedHashMap<>(); + for (CtTypeReference reference : + workspace.model().getElements(new TypeFilter<>(CtTypeReference.class))) { + typeReferencesBySimpleName + .computeIfAbsent(reference.getSimpleName(), ignored -> new ArrayList<>()) + .add(reference); + } + typeDeclarationsBySimpleName = new LinkedHashMap<>(); + for (CtType declaration : workspace.model().getAllTypes()) { + typeDeclarationsBySimpleName + .computeIfAbsent( + declaration.getSimpleName(), ignored -> new java.util.LinkedHashSet<>()) + .add(declaration.getQualifiedName()); + } + } + + /** + * Rewrites uses of individual incarnation types to their configured common grouping types. + * + *

For {@code {CreditCard=PaymentMethod, Invoice=PaymentMethod}}, a shared {@code + * List} may become {@code List}. The concrete incarnation declarations + * themselves are not renamed, builder declarations retain their concrete types, and a method + * parameter is left unchanged when grouping it would collapse two overloads to the same Java + * signature. + */ + private void applyGroupingToModel() { + if (groupingMappings.isEmpty()) { + return; + } + Set> concreteDeclarations = + workspace.model().getAllTypes().stream() + .filter(type -> mappingFor(type.getReference()) != null) + .collect(Collectors.toCollection(HashSet::new)); + for (CtTypeReference reference : + workspace.model().getElements(new TypeFilter<>(CtTypeReference.class))) { + String replacement = mappingFor(reference); + if (replacement == null) { + continue; + } + CtType owner = reference.getParent(CtType.class); + if (owner != null + && (concreteDeclarations.contains(owner) + || (owner.getSimpleName() != null && owner.getSimpleName().endsWith("Builder")))) { + continue; + } + if (wouldCollapseOverload(reference)) { + continue; + } + if (!replacement.equals(reference.getSimpleName())) { + rewriteTypeReferenceName(reference, replacement); + } + } + } + + /** + * Keeps concrete parameter types when replacing them by a grouping type would erase overload + * identity. This is required for overload sets introduced by CD completion, such as Visitor + * methods for several concrete node incarnations. + */ + private boolean wouldCollapseOverload(CtTypeReference reference) { + CtParameter parameter = reference.getParent(CtParameter.class); + if (parameter == null || parameter.getType() != reference) { + return false; + } + CtMethod method = parameter.getParent(CtMethod.class); + CtType owner = method == null ? null : method.getParent(CtType.class); + if (owner == null) { + return false; + } + String groupedSignature = groupedSignature(method); + return owner.getMethods().stream() + .filter(candidate -> candidate != method) + .anyMatch(candidate -> groupedSignature.equals(groupedSignature(candidate))); + } + + private String groupedSignature(CtMethod method) { + return method.getSimpleName() + + "(" + + method.getParameters().stream() + .map(CtParameter::getType) + .map( + type -> { + String grouping = mappingFor(type); + return grouping == null + ? type.getSimpleName() + : JavaSourceNames.simpleName(grouping); + }) + .collect(Collectors.joining(",")) + + ")"; + } + + /** + * Resolves the grouping replacement applicable to one Spoon type reference. + * + *

A qualified map key must match the reference's qualified identity. A simple key is accepted + * only when exactly one loaded declaration has that simple name and the reference resolves to it + * (or, when unresolved, is used from the same package). This prevents a mapping for {@code + * billing.Invoice} from rewriting an unrelated {@code shipping.Invoice}. + */ + private String mappingFor(CtTypeReference reference) { + String qualifiedName = reference.getQualifiedName(); + if (qualifiedName != null && groupingMappings.containsKey(qualifiedName)) { + return groupingMappings.get(qualifiedName); + } + String simpleName = reference.getSimpleName(); + if (!groupingMappings.containsKey(simpleName)) { + return null; + } + Set qualifiedKeys = + groupingMappings.keySet().stream() + .filter(key -> key.endsWith("." + simpleName)) + .collect(Collectors.toSet()); + if (!qualifiedKeys.isEmpty()) { + return qualifiedKeys.contains(qualifiedName) ? groupingMappings.get(qualifiedName) : null; + } + List> declarations = + workspace.model().getAllTypes().stream() + .filter(type -> simpleName.equals(type.getSimpleName())) + .toList(); + if (declarations.size() != 1) { + return null; + } + CtType declaration = declarations.get(0); + Optional identity = resolvedTypeIdentity(reference); + if (identity.isPresent() && !declaration.getQualifiedName().equals(identity.get())) { + return null; + } + if (identity.isEmpty()) { + CtType owner = reference.getParent(CtType.class); + String ownerPackage = + owner == null || owner.getPackage() == null ? "" : owner.getPackage().getQualifiedName(); + String declarationPackage = + declaration.getPackage() == null ? "" : declaration.getPackage().getQualifiedName(); + if (!ownerPackage.equals(declarationPackage)) { + return null; + } + } + return groupingMappings.get(simpleName); + } + + /** Rewrites a type reference while retaining valid package identity for simple replacements. */ + private void rewriteTypeReferenceName(CtTypeReference reference, String newName) { + if (reference == null || newName == null || newName.isBlank()) { + throw new IllegalArgumentException("Type reference and new name must be present"); + } + String simpleName = JavaSourceNames.simpleName(newName); + if (newName.contains(".")) { + CtTypeReference replacement = workspace.createTypeReference(newName); + reference.setPackage(replacement.getPackage()); + reference.setDeclaringType(replacement.getDeclaringType()); + } + // For a simple replacement, retain the original package identity. Turning entity.User into + // an unresolved simple Professor produces an invalid import that cleanup can only remove. + reference.setSimpleName(simpleName); + reference.setSimplyQualified(true); + } + + private static Optional resolvedTypeIdentity(CtTypeReference reference) { + try { + CtType declaration = reference.getTypeDeclaration(); + if (declaration != null && declaration.getQualifiedName() != null) { + return Optional.of(declaration.getQualifiedName()); + } + } catch (RuntimeException ignored) { + // no-classpath references often have no declaration; retain qualified metadata below. + } + String qualifiedName = reference.getQualifiedName(); + if (qualifiedName == null + || qualifiedName.isBlank() + || qualifiedName.equals(reference.getSimpleName())) { + return Optional.empty(); + } + return Optional.of(qualifiedName); + } + + private static T selectUnique(List matches, String name) { + if (matches.size() != 1) { + throw new IllegalStateException( + "Expected exactly one Spoon declaration named '" + name + "' but found " + matches.size()); + } + return matches.get(0); + } + + private static > T selectByPosition( + List matches, int sourceLine, String name) { + if (matches.size() == 1) { + return matches.get(0); + } + List sameLine = + matches.stream() + .filter(variable -> variable.getPosition().isValidPosition()) + .filter(variable -> variable.getPosition().getLine() == sourceLine) + .collect(Collectors.toList()); + return selectUnique(sameLine, name + " at line " + sourceLine); + } + + private static void renameVariable(CtVariable variable, String newName) { + CtRenameGenericVariableRefactoring refactoring = new CtRenameGenericVariableRefactoring(); + refactoring.setTarget(variable).setNewName(newName).refactor(); + } + +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonUpdater.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonUpdater.java index 9f26c4b5..fc554485 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonUpdater.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonUpdater.java @@ -1,272 +1,191 @@ package de.monticore.codeAdaption.updater.spoonUpdater; -import static de.monticore.codeAdaption.utils.JavaLoader.print; - import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; import de.monticore.codeAdaption.updater.CodeUpdater; -import de.monticore.codeAdaption.utils.JavaLoader; import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; import de.monticore.java.javadsl._ast.ASTTypeDeclaration; import de.monticore.javalight._ast.ASTMethodDeclaration; import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; -import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.io.File; import java.nio.file.Path; -import java.util.*; -import spoon.Launcher; -import spoon.refactoring.CtRenameGenericVariableRefactoring; -import spoon.refactoring.Refactoring; -import spoon.reflect.CtModel; -import spoon.reflect.code.CtLocalVariable; -import spoon.reflect.declaration.*; -import spoon.reflect.reference.CtTypeReference; +import java.util.List; +import java.util.Map; +import java.util.Set; +/** Spoon-backed facade for loading, transforming, generating and printing Java source code. */ public class SpoonUpdater implements CodeUpdater { - private File outputDir; - private Launcher launcher; - private CtModel spoonModel; - private final Map> typeMap = new LinkedHashMap<>(); - private final Map> methodMap = new LinkedHashMap<>(); + private final SpoonWorkspace workspace; + private final SpoonElementResolver elementResolver; + private final SpoonExecutableRepairService executableRepairs; + private final SpoonTransformationService transformations; + private final SpoonGenerationService generation; + + public SpoonUpdater() { + workspace = new SpoonWorkspace(); + elementResolver = new SpoonElementResolver(workspace::model); + executableRepairs = new SpoonExecutableRepairService(workspace, elementResolver); + transformations = + new SpoonTransformationService(workspace, elementResolver, executableRepairs); + generation = new SpoonGenerationService(workspace, elementResolver); + } @Override public void setCodePath(Path path) { - // init spoon environment - launcher = new Launcher(); - launcher.getEnvironment().setAutoImports(true); - launcher.getEnvironment().setShouldCompile(true); + workspace.load(path); + elementResolver.reset(); + transformations.reset(); + executableRepairs.reset(); + } - // add code to the environment - launcher.addInputResource(path.toAbsolutePath().toString()); + @Override + public Set printCode() { + transformations.prepareForPrint(); + return workspace.print(); + } - // build model - launcher.buildModel(); - spoonModel = launcher.getModel(); + @Override + public void cleanCode(Path codePath) { + workspace.clean(codePath); } @Override - public Set printCode() { - launcher.setSourceOutputDirectory(outputDir); - launcher.prettyprint(); - return JavaLoader.readJavaFile(outputDir.toPath()); + public void setGroupingMappings(Map mappings) { + transformations.setGroupingMappings(mappings); + } + + @Override + public void registerConcreteMethodSignature(String methodName, List parameterTypes) { + executableRepairs.registerConcreteMethodSignature(methodName, parameterTypes); + } + + @Override + public void registerMethodRewrite( + StableElementKey referenceMethod, StableElementKey concreteMethod) { + executableRepairs.registerMethodRewrite(referenceMethod, concreteMethod); } @Override public void updateType(ASTTypeDeclaration source, String newName) { - CtType type = getSpoonType(source); - Refactoring.changeTypeName(type, newName); + transformations.updateType(source, newName); } @Override public void updateMethod( - ASTTypeDeclaration srcType, ASTMethodDeclaration srcMethod, String newName) { - CtMethod method = getSpoonMethod(srcType, srcMethod); - Refactoring.changeMethodName(method, newName); + ASTTypeDeclaration sourceType, ASTMethodDeclaration sourceMethod, String newName) { + transformations.updateMethod(sourceType, sourceMethod, newName); } @Override public void updateField( - ASTTypeDeclaration srcType, ASTFieldDeclaration srcField, String newName) { - - // get Spoon Variable - String srcName = srcField.getVariableDeclarator(0).getDeclarator().getName(); - CtVariable attribute = getSpoonType(srcType).getField(srcName); + ASTTypeDeclaration sourceType, ASTFieldDeclaration sourceField, String newName) { + transformations.updateField(sourceType, sourceField, newName); + } - // perform update - CtRenameGenericVariableRefactoring refactor = new CtRenameGenericVariableRefactoring(); - refactor.setTarget(attribute).setNewName(newName).refactor(); + @Override + public void updateAssociationRole( + ASTTypeDeclaration sourceType, String sourceRole, String concreteRole) { + transformations.updateAssociationRole(sourceType, sourceRole, concreteRole); } @Override public void updateSuperType(ASTTypeDeclaration type, ASTMCType supertype, String newName) { - String srcName = JavaLoader.print(supertype); - CtType spoonType = getSpoonType(type); - - // case super class - CtTypeReference superType = spoonType.getSuperclass(); - if (superType != null && superType.getSimpleName().equals(srcName)) { - spoonType.getSuperclass().setSimpleName(newName); - return; - } - - // case super interface - for (CtTypeReference superType2 : spoonType.getSuperInterfaces()) { - if (superType2.getSimpleName().equals(srcName)) { - superType2.setSimpleName(newName); - } - } + transformations.updateSuperType(type, supertype, newName); } @Override public void updateLocalVariable( - ASTTypeDeclaration srcType, - ASTMethodDeclaration srcMethod, - ASTLocalVariableDeclaration sourceVar, + ASTTypeDeclaration sourceType, + ASTMethodDeclaration sourceMethod, + ASTLocalVariableDeclaration sourceVariable, String newName) { - - // get spoon local-variable - CtMethod spoonMethod = getSpoonMethod(srcType, srcMethod); - List> localVars = spoonMethod.getElements(Objects::nonNull); - String varName = sourceVar.getVariableDeclarator(0).getDeclarator().getName(); - Optional> var = - localVars.stream().filter(v -> v.getSimpleName().equals(varName)).findAny(); - assert var.isPresent(); - - // perform update - CtRenameGenericVariableRefactoring refactor = new CtRenameGenericVariableRefactoring(); - refactor.setTarget(var.get()).setNewName(newName).refactor(); + transformations.updateLocalVariable( + sourceType, sourceMethod, sourceVariable, newName); } @Override public void updateMethodParameter( - ASTTypeDeclaration srcType, - ASTMethodDeclaration srcMethod, - ASTFormalParameter srcParam, + ASTTypeDeclaration sourceType, + ASTMethodDeclaration sourceMethod, + ASTFormalParameter sourceParameter, String newName) { - - // get spoon formal parameter of method - CtMethod spoonMethod = getSpoonMethod(srcType, srcMethod); - List> params = spoonMethod.getElements(Objects::nonNull); - String srcVarName = srcParam.getDeclarator().getName(); - Optional> param = - params.stream().filter(v -> v.getSimpleName().equals(srcVarName)).findAny(); - - if (param.isPresent()) { - // perform update - CtRenameGenericVariableRefactoring refactor = new CtRenameGenericVariableRefactoring(); - refactor.setTarget(param.get()).setNewName(newName).refactor(); - - } else { - - // case formal param in for loop - List> localVars = spoonMethod.getElements(Objects::nonNull); - Optional> localvar = - localVars.stream().filter(v -> v.getSimpleName().equals(srcVarName)).findAny(); - assert localvar.isPresent(); - - // case formal param in for loop - CtRenameGenericVariableRefactoring refactor = new CtRenameGenericVariableRefactoring(); - refactor.setTarget(localvar.get()).setNewName(newName).refactor(); - } + transformations.updateMethodParameter( + sourceType, sourceMethod, sourceParameter, newName); } @Override - public void updateCDType(ASTCDType cdType, String newName) { - List> refTypes = spoonModel.getElements(Objects::nonNull); - - for (CtTypeReference typeRef : refTypes) { - if (typeRef.getSimpleName().equals(cdType.getName())) { - typeRef.setSimpleName(newName); - } - } - - // for () + public void updateCDType(ASTCDType type, String newName) { + transformations.updateCDType(type, newName); } @Override public void setOutputDirectory(Path outputPath) { - this.outputDir = outputPath.toFile(); + workspace.setOutputDirectory(outputPath); + } + + @Override + public void addField( + ASTTypeDeclaration targetType, + ASTFieldDeclaration templateField, + String newName, + String newType, + boolean isStatic) { + generation.addField(targetType, templateField, newName, newType, isStatic); } - /*** - * Retrieves the spoonType from the Spoon Model based on the provided mcType. - * Saves the found spoonType in the type map. - * - * @param mcType The ASTTypeDeclaration representing the type to be searched - * for in the Spoon model. - * @return The corresponding CtType found in the Spoon model for the - * given mcType. - * @throws AssertionError if no matching CtType is found in the Spoon - * model (assert will fail). - */ - private CtType getSpoonType(ASTTypeDeclaration mcType) { - // cas already found - if (typeMap.containsKey(mcType)) { - return typeMap.get(mcType); - } - // search in the spoon model - Optional> type = - spoonModel.getAllTypes().stream().filter(t -> compare(mcType, t)).findFirst(); - assert type.isPresent(); - typeMap.put(mcType, type.get()); - return type.get(); + @Override + public void addType(ASTTypeDeclaration templateType, String newName) { + generation.addType(templateType, newName); } - /*** - * Retrieves the spoonMethod from the Spoon Model based on the provided - * mcType and mcMethod. Saves the found spoonMethod in the method map. - * - * @param mcType The ASTTypeDeclaration representing the type to which - * the method belongs. - * @param mcMethod The ASTMethodDeclaration representing the method to be - * searched for in the Spoon model. - * @return The corresponding CtMethod found in the Spoon model for the - * given mcType and mcMethod. - * @throws AssertionError if no matching CtMethod is found in the - * Spoon model (assert will fail). - */ - public CtMethod getSpoonMethod(ASTTypeDeclaration mcType, ASTMethodDeclaration mcMethod) { - // cas method was already found - if (methodMap.containsKey(mcMethod)) { - return methodMap.get(mcMethod); - } + @Override + public void addSuperType( + ASTTypeDeclaration targetType, String superTypeName, boolean interfaceType) { + generation.addSuperType(targetType, superTypeName, interfaceType); + } - // search method in the spoonType - CtType spoonType = getSpoonType(mcType); - Optional> method = - spoonType.getAllMethods().stream() - .filter(spMethod -> compare(mcMethod, spMethod)) - .findFirst(); + @Override + public void setTypeAbstract(ASTTypeDeclaration targetType, boolean isAbstract) { + generation.setTypeAbstract(targetType, isAbstract); + } - assert method.isPresent(); - methodMap.put(mcMethod, method.get()); - return method.get(); + @Override + public void addEnumConstant( + ASTTypeDeclaration targetType, String constantName, int expectedIndex) { + generation.addEnumConstant(targetType, constantName, expectedIndex); } - /** - * Compares a mcType and spoonType and returns true if both are identical. - * - * @param type The ASTTypeDeclaration representing the type to be compared. - * @param spoonType The CtType representing the spoon type to be compared. - * @return True if the file name of the mcType ends with the simple name of the spoonType followed - * by ".java"; otherwise false. - */ - protected boolean compare(ASTTypeDeclaration type, CtType spoonType) { - String fileName = type.get_SourcePositionStart().getFileName().orElse(type.getName()); - return fileName.replaceAll("\\\\", ".").endsWith(spoonType.getSimpleName() + ".java"); + @Override + public void addMethod( + ASTTypeDeclaration targetType, + ASTMethodDeclaration templateMethod, + String newName, + List parameterTypes, + List parameterNames, + String returnType, + boolean isStatic, + MethodBodySpec methodBody) { + generation.addMethod( + targetType, + templateMethod, + newName, + parameterTypes, + parameterNames, + returnType, + isStatic, + methodBody); } - /** - * Compares a spoonMethod and mcMethod and returns true if both are identical. - * - * @param mcMethod The ASTMethodDeclaration representing the method to be compared. - * @param spoonMethod The CtMethod representing the spoon method to be compared. - * @return True if the names, parameter count, and parameter types of both methods match; - * otherwise false. - */ - protected boolean compare(ASTMethodDeclaration mcMethod, CtMethod spoonMethod) { - // compare names - if (!mcMethod.getName().endsWith(spoonMethod.getSimpleName())) { - return false; - } - // is present parameters ? - if (!mcMethod.getFormalParameters().isPresentFormalParameterListing()) { - return spoonMethod.getParameters().isEmpty(); - } - // same number of parameters ? - List mcParams = - mcMethod.getFormalParameters().getFormalParameterListing().getFormalParameterList(); - if (spoonMethod.getParameters().size() != mcParams.size()) { - return false; - } - // parameters have the same type ? - for (int i = 0; i < spoonMethod.getParameters().size(); i++) { - if (!(spoonMethod.getParameters().get(i).getType().getSimpleName()) - .equals(print(mcParams.get(i).getMCType()))) { - return false; - } - } + @Override + public void removeField(ASTTypeDeclaration targetType, ASTFieldDeclaration field) { + generation.removeField(targetType, field); + } - return true; + @Override + public void removeMethod(ASTTypeDeclaration targetType, ASTMethodDeclaration method) { + generation.removeMethod(targetType, method); } + } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonWorkspace.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonWorkspace.java new file mode 100644 index 00000000..e2eb9111 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonWorkspace.java @@ -0,0 +1,424 @@ +package de.monticore.codeAdaption.updater.spoonUpdater; + +import de.monticore.codeAdaption.utils.AdaptAnnotationNames; +import de.monticore.codeAdaption.utils.Constants; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.codeAdaption.utils.JavaSourcePostProcessor; +import de.se_rwth.commons.logging.Log; +import java.io.File; +import java.io.IOException; +import java.nio.file.AtomicMoveNotSupportedException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.io.FileUtils; +import spoon.Launcher; +import spoon.reflect.CtModel; +import spoon.reflect.code.CtExpression; +import spoon.reflect.declaration.CtAnnotation; +import spoon.reflect.declaration.CtField; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.ModifierKind; +import spoon.reflect.factory.Factory; +import spoon.reflect.reference.CtTypeReference; +import spoon.reflect.visitor.filter.TypeFilter; +import spoon.support.compiler.VirtualFile; + +/** Owns the Spoon model, its factory and the generated-source filesystem lifecycle. */ +final class SpoonWorkspace { + private static final Pattern SOURCE_ANNOTATION_NAME = + Pattern.compile("^\\s*@\\s*([A-Za-z_$][\\w$]*(?:\\s*\\.\\s*[A-Za-z_$][\\w$]*)*)"); + private final Map>> parsedTypePrototypes = + new LinkedHashMap<>(); + private File outputDirectory; + private Launcher launcher; + private CtModel model; + + void load(Path codePath) { + try { + JavaSourcePostProcessor.processDirectory(codePath); + } catch (IOException e) { + throw new IllegalStateException( + "SpoonUpdater.setCodePath: Failed to prepare source code at '" + codePath + "'", e); + } + launcher = new Launcher(); + launcher.getEnvironment().setAutoImports(true); + launcher.getEnvironment().setNoClasspath(true); + launcher.addInputResource(codePath.toAbsolutePath().toString()); + launcher.buildModel(); + model = launcher.getModel(); + parsedTypePrototypes.clear(); + } + + CtModel model() { + if (model == null) { + throw new IllegalStateException("No Spoon model loaded; call setCodePath first"); + } + return model; + } + + Factory factory() { + if (launcher == null) { + throw new IllegalStateException("No Spoon workspace loaded; call setCodePath first"); + } + return launcher.getFactory(); + } + + void setOutputDirectory(Path outputPath) { + if (outputPath == null) { + throw new IllegalArgumentException("Output path must not be null"); + } + outputDirectory = outputPath.toFile(); + } + + Set print() { + if (outputDirectory == null) { + throw new IllegalStateException("No output directory configured"); + } + Path outputPath = outputDirectory.toPath(); + try { + if (Files.isDirectory(outputPath)) { + try (var paths = Files.walk(outputPath)) { + for (Path source : + paths.filter(Files::isRegularFile) + .filter(path -> path.toString().endsWith(".java")) + .toList()) { + Files.delete(source); + } + } + } + } catch (IOException exception) { + throw new IllegalStateException( + "Failed to clear stale Java sources before printing to " + outputPath, exception); + } + launcher.setSourceOutputDirectory(outputDirectory); + launcher.prettyprint(); + return JavaLoader.readJavaFile(outputPath); + } + + CtExpression defaultExpression(String typeName) { + String normalized = typeName == null ? "" : JavaSourceNames.normalizeType(typeName.trim()); + return switch (normalized) { + case "boolean" -> factory().Code().createLiteral(false); + case "byte" -> factory().Code().createLiteral((byte) 0); + case "short" -> factory().Code().createLiteral((short) 0); + case "int" -> factory().Code().createLiteral(0); + case "long" -> factory().Code().createLiteral(0L); + case "float" -> factory().Code().createLiteral(0.0f); + case "double" -> factory().Code().createLiteral(0.0d); + case "char" -> factory().Code().createLiteral('\0'); + default -> factory().Code().createLiteral(null); + }; + } + + CtTypeReference createTypeReference(String typeName) { + if (typeName == null || typeName.isBlank()) { + return factory().Type().createReference(Object.class); + } + String original = typeName.trim(); + Optional> parsed = parseTypePrototype(original); + if (parsed.isPresent()) { + return parsed.get().clone(); + } + String normalized = JavaSourceNames.normalizeType(original); + CtTypeReference primitive = primitiveTypeReference(normalized); + if (primitive != null) { + return primitive; + } + parsed = parseTypePrototype(normalized); + if (parsed.isPresent()) { + return parsed.get().clone(); + } + try { + return factory().Type().createReference(normalized); + } catch (RuntimeException ignored) { + return unresolvedTypeReference(normalized); + } + } + + void clean(Path codePath) { + Path sourcePath = codePath.toAbsolutePath().normalize(); + if (!Files.isDirectory(sourcePath)) { + throw new IllegalArgumentException("Code path is not a directory: " + sourcePath); + } + Path parent = sourcePath.getParent(); + if (parent == null) { + throw new IllegalArgumentException("Cannot transactionally clean a filesystem root"); + } + Path transactionRoot = null; + boolean preserveTransaction = false; + try { + transactionRoot = + Files.createTempDirectory(parent, sourcePath.getFileName() + "_cleanup_"); + Path formattedPath = transactionRoot.resolve("formatted"); + Path stagedPath = transactionRoot.resolve("staged"); + Files.createDirectories(formattedPath); + FileUtils.copyDirectory(sourcePath.toFile(), stagedPath.toFile()); + Map originals = javaFilesByRelativePath(sourcePath); + Launcher cleanupLauncher = cleanupLauncher(sourcePath); + List> annotations = + new ArrayList<>(cleanupLauncher.getModel().getElements(new TypeFilter<>(CtAnnotation.class))); + cleanAdaptAnnotations(cleanupLauncher, annotations); + for (CtType type : cleanupLauncher.getModel().getAllTypes()) { + if (!type.isInterface()) { + continue; + } + for (CtMethod method : type.getMethods()) { + if (!method.isDefaultMethod() + && !method.hasModifier(ModifierKind.STATIC) + && !method.hasModifier(ModifierKind.PRIVATE)) { + method.setBody(null); + } + } + } + cleanupLauncher.setSourceOutputDirectory(formattedPath.toFile()); + cleanupLauncher.prettyprint(); + Set copiedTargets = + copyFormattedFiles(formattedPath, stagedPath, sourcePath, originals); + deleteRehomedOriginals(sourcePath, stagedPath, originals.values(), copiedTargets); + JavaSourcePostProcessor.processDirectory(stagedPath); + commitStagedDirectory(sourcePath, stagedPath, transactionRoot.resolve("backup")); + Log.info("SpoonUpdater.cleanCode: Cleanup completed", "CodeAdapter"); + } catch (IOException | RuntimeException e) { + if (transactionRoot != null && Files.exists(transactionRoot.resolve("backup"))) { + preserveTransaction = true; + } + throw new IllegalStateException( + "SpoonUpdater.cleanCode: Failed to clean code at '" + sourcePath + "'", e); + } finally { + if (transactionRoot != null && !preserveTransaction) { + FileUtils.deleteQuietly(transactionRoot.toFile()); + } + } + } + + private Optional> parseTypePrototype(String typeName) { + return parsedTypePrototypes.computeIfAbsent(typeName, this::parseTypeReference); + } + + private Optional> parseTypeReference(String typeName) { + try { + Launcher parser = new Launcher(); + parser.getEnvironment().setNoClasspath(true); + parser.addInputResource( + new VirtualFile("class __TypeProbe { " + typeName + " value; }", "__TypeProbe.java")); + parser.buildModel(); + return parser.getModel().getElements(new TypeFilter<>(CtField.class)).stream() + .findFirst() + .map(field -> field.getType().clone()); + } catch (RuntimeException ignored) { + return Optional.empty(); + } + } + + private CtTypeReference primitiveTypeReference(String typeName) { + return switch (typeName) { + case "void" -> factory().Type().createReference(void.class); + case "int" -> factory().Type().createReference(int.class); + case "long" -> factory().Type().createReference(long.class); + case "double" -> factory().Type().createReference(double.class); + case "float" -> factory().Type().createReference(float.class); + case "boolean" -> factory().Type().createReference(boolean.class); + case "char" -> factory().Type().createReference(char.class); + case "short" -> factory().Type().createReference(short.class); + case "byte" -> factory().Type().createReference(byte.class); + default -> null; + }; + } + + private CtTypeReference unresolvedTypeReference(String typeName) { + CtTypeReference reference = factory().Core().createTypeReference(); + String simpleName = JavaSourceNames.simpleName(typeName); + reference.setSimpleName(simpleName.isBlank() ? "Object" : simpleName); + reference.setPackage(null); + reference.setDeclaringType(null); + reference.setSimplyQualified(true); + return reference; + } + + private static Launcher cleanupLauncher(Path codePath) throws IOException { + Launcher cleanupLauncher = new Launcher(); + cleanupLauncher.getEnvironment().setAutoImports(true); + cleanupLauncher.getEnvironment().setNoClasspath(true); + try (var paths = Files.walk(codePath)) { + paths.filter(Files::isRegularFile) + .filter(path -> path.toString().endsWith(".java")) + .forEach(path -> cleanupLauncher.addInputResource(path.toAbsolutePath().toString())); + } + cleanupLauncher.buildModel(); + return cleanupLauncher; + } + + private static Map javaFilesByRelativePath(Path codePath) throws IOException { + Map result = new LinkedHashMap<>(); + try (var paths = Files.walk(codePath)) { + paths.filter(Files::isRegularFile) + .filter(path -> path.toString().endsWith(".java")) + .forEach(path -> result.put(codePath.relativize(path), path)); + } + return result; + } + + private static Set copyFormattedFiles( + Path formattedPath, Path stagedPath, Path sourcePath, Map originals) + throws IOException { + Set copiedTargets = new LinkedHashSet<>(); + try (var paths = Files.walk(formattedPath)) { + paths.filter(Files::isRegularFile) + .filter(path -> path.toString().endsWith(".java")) + .forEach( + source -> { + try { + Path relative = formattedPath.relativize(source); + Path originalTarget = originals.getOrDefault(relative, sourcePath.resolve(relative)); + Path target = stagedPath.resolve(sourcePath.relativize(originalTarget)); + Files.createDirectories(target.getParent()); + copyReplacingWithRetry(source, target); + if (!copiedTargets.add(target.toAbsolutePath().normalize())) { + throw new IllegalStateException( + "Multiple formatted sources target the same file '" + target + "'"); + } + } catch (IOException e) { + throw new IllegalStateException("Failed to copy formatted file '" + source + "'", e); + } + }); + } + return copiedTargets; + } + + private static void deleteRehomedOriginals( + Path sourcePath, + Path stagedPath, + Collection originals, + Set copiedTargets) + throws IOException { + for (Path original : originals) { + Path stagedOriginal = stagedPath.resolve(sourcePath.relativize(original)); + if (!copiedTargets.contains(stagedOriginal.toAbsolutePath().normalize()) + && Files.exists(stagedOriginal)) { + Files.delete(stagedOriginal); + } + } + } + + private static void commitStagedDirectory(Path source, Path staged, Path backup) + throws IOException { + moveDirectory(source, backup); + try { + moveDirectory(staged, source); + } catch (IOException commitFailure) { + try { + moveDirectory(backup, source); + } catch (IOException rollbackFailure) { + commitFailure.addSuppressed(rollbackFailure); + } + throw commitFailure; + } + FileUtils.deleteDirectory(backup.toFile()); + } + + private static void moveDirectory(Path source, Path target) throws IOException { + try { + Files.move(source, target, StandardCopyOption.ATOMIC_MOVE); + } catch (AtomicMoveNotSupportedException ignored) { + Files.move(source, target); + } + } + + private static void copyReplacingWithRetry(Path source, Path target) throws IOException { + IOException lastException = null; + for (int attempt = 0; attempt < 5; attempt++) { + try { + Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); + return; + } catch (IOException e) { + lastException = e; + try { + Thread.sleep(50L * (attempt + 1)); + } catch (InterruptedException interrupted) { + Thread.currentThread().interrupt(); + throw e; + } + } + } + throw lastException; + } + + private static boolean isAdaptAnnotation(CtAnnotation annotation) { + Optional sourceName = sourceAnnotationName(annotation); + if (sourceName.isPresent()) { + return AdaptAnnotationNames.matches(sourceName.get()); + } + CtTypeReference type = annotation.getAnnotationType(); + if (type != null) { + String simple = type.getSimpleName(); + String qualified = type.getQualifiedName(); + if (Constants.ANNOT_PACKAGE.equals(qualified) + || (Constants.ANNOT_NAME.equals(simple) + && (qualified == null + || qualified.isBlank() + || Constants.ANNOT_NAME.equals(qualified)))) { + return true; + } + } + String rendered = annotation.toString().trim(); + return hasAnnotationPrefix(rendered, Constants.ANNOT_NAME) + || hasAnnotationPrefix(rendered, Constants.ANNOT_PACKAGE); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static void cleanAdaptAnnotations( + Launcher cleanupLauncher, List> annotations) { + for (CtAnnotation annotation : annotations) { + Optional sourceName = sourceAnnotationName(annotation); + if (sourceName.filter(AdaptAnnotationNames::matches).isPresent() + || (sourceName.isEmpty() && isAdaptAnnotation(annotation))) { + annotation.delete(); + } else if (sourceName.filter(name -> name.contains(".")).isPresent()) { + CtTypeReference originalType = + cleanupLauncher.getFactory().Type().createReference(sourceName.get()); + originalType.setSimplyQualified(false); + ((CtAnnotation) annotation).setAnnotationType(originalType); + } + } + } + + private static Optional sourceAnnotationName(CtAnnotation annotation) { + try { + if (annotation.getPosition() == null || !annotation.getPosition().isValidPosition()) { + return Optional.empty(); + } + String source = annotation.getPosition().getCompilationUnit().getOriginalSourceCode(); + int start = annotation.getPosition().getSourceStart(); + int end = annotation.getPosition().getSourceEnd(); + if (source == null || start < 0 || end < start || end >= source.length()) { + return Optional.empty(); + } + Matcher matcher = SOURCE_ANNOTATION_NAME.matcher(source.substring(start, end + 1)); + return matcher.find() + ? Optional.of(matcher.group(1).replaceAll("\\s+", "")) + : Optional.empty(); + } catch (RuntimeException ignored) { + return Optional.empty(); + } + } + + private static boolean hasAnnotationPrefix(String rendered, String annotationName) { + String prefix = "@" + annotationName; + return rendered.equals(prefix) + || rendered.startsWith(prefix + "(") + || rendered.startsWith(prefix + "["); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Adapt.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Adapt.java index c3709db4..03396fc9 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Adapt.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Adapt.java @@ -3,6 +3,14 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Target; +/** + * Declares how a handwritten Java element relates to reference-CD elements. + * + *

The annotation may be placed on types, fields, methods, parameters, and local variables. + * Explicit annotation matching takes precedence when {@link AdapterParam#ANNOTATION_MATCHING} is + * enabled. Templates consume references from left to right using {@code ${}}, {@code + * ${cap_first}}, and {@code ${uncap_first}} placeholders. + */ @Target({ ElementType.LOCAL_VARIABLE, ElementType.TYPE, @@ -11,9 +19,34 @@ ElementType.PARAMETER, }) public @interface Adapt { + /** Returns whether the annotated Java element is intentionally excluded from adaptation. */ boolean ignore() default false; + /** + * Returns the qualified or owner-relative reference-CD element names represented by this Java + * element. + * + *

For methods, {@code Order.update} selects a unique method by name, {@code Order.update()} + * selects the zero-parameter overload, and {@code Order.update(int)} selects the overload with an + * {@code int} parameter. + */ String[] ref() default {}; + /** + * Returns the name template used to validate and adapt the existing handwritten element. + * + *

For example, {@code ref={"Entity", "Entity.id"}} with {@code + * template="find${}By${cap_first}"} produces {@code findPersonByNumber} when those references map + * to {@code Person} and {@code number}. Placeholders consume references from left to right. + */ String template() default ""; + + /** + * Returns the optional template used when a new name or declaration is generated. + * + *

For example, {@code template="${}"} validates an adapter type while {@code + * genTemplate="${}Builder"} generates {@code PersonBuilder}. An empty value reuses the ordinary + * template where generation supports that fallback. + */ + String genTemplate() default ""; } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdaptAnnotationNames.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdaptAnnotationNames.java new file mode 100644 index 00000000..5eae41ea --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdaptAnnotationNames.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.utils; + +/** Compares annotation AST names with the supported simple and qualified {@link Adapt} names. */ +public final class AdaptAnnotationNames { + + private AdaptAnnotationNames() {} + + /** Returns whether the supplied AST qualified name denotes {@link Adapt}. */ + public static boolean matches(String qualifiedName) { + return Constants.ANNOT_NAME.equals(qualifiedName) + || Constants.ANNOT_PACKAGE.equals(qualifiedName); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdaptReference.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdaptReference.java new file mode 100644 index 00000000..32006465 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdaptReference.java @@ -0,0 +1,95 @@ +package de.monticore.codeAdaption.utils; + +import de.monticore.java.javadsl.JavaDSLMill; +import java.io.IOException; +import java.util.Objects; +import java.util.Optional; + +/** + * Parsed reference to a type, field, or method used by {@code @Adapt} mappings. + * + *

References may be local, such as {@code name} and {@code update(String)}, or owner-qualified, + * such as {@code model.Order.name} and {@code model.Order.update(java.time.Instant)}. The owner is + * separated only before the method's opening parenthesis, while JavaDSL validates owner and method + * syntax and normalizes parameter types through {@link JavaMethodSignatures}. + * + *

The small amount of delimiter handling in this class is intentional: an adapter method + * reference contains parameter types without parameter names, so it is neither a Java invocation + * nor a Java declaration that JavaDSL could parse as a whole. All nested Java type syntax is still + * delegated to JavaDSL. + * + * @param owner optional qualified owner preceding the referenced member + * @param memberName unqualified type or member name + * @param methodSignature normalized method signature when the reference denotes a method + */ +public record AdaptReference( + Optional owner, String memberName, Optional methodSignature) { + + public AdaptReference { + owner = Objects.requireNonNull(owner, "owner"); + memberName = Objects.requireNonNull(memberName, "memberName"); + methodSignature = Objects.requireNonNull(methodSignature, "methodSignature"); + } + + /** + * Parses one adapter reference without confusing dots in qualified parameter types with the + * owner/member separator. + * + * @param value textual adapter reference + * @return the parsed reference, or empty when its owner, member, or signature is malformed + */ + public static Optional parse(String value) { + if (value == null || value.isBlank()) { + return Optional.empty(); + } + String reference = value.trim(); + int open = reference.indexOf('('); + int memberEnd = open < 0 ? reference.length() : open; + int separator = reference.lastIndexOf('.', memberEnd - 1); + String owner = separator < 0 ? "" : reference.substring(0, separator).trim(); + String memberReference = reference.substring(separator + 1).trim(); + + if ((separator >= 0 && owner.isEmpty()) || memberReference.isEmpty() || !isOwner(owner)) { + return Optional.empty(); + } + if (open >= 0 || reference.indexOf(')') >= 0) { + Optional signature = JavaMethodSignatures.parseNormalized(memberReference); + if (signature.isEmpty()) { + return Optional.empty(); + } + return Optional.of( + new AdaptReference( + optional(owner), JavaSourceNames.simpleName(signature.get()), signature)); + } + if (JavaMethodSignatures.parseNormalized(memberReference + "()").isEmpty()) { + return Optional.empty(); + } + return Optional.of( + new AdaptReference(optional(owner), memberReference, Optional.empty())); + } + + /** Returns the normalized member reference, including parameters for methods. */ + public String memberReference() { + return methodSignature.orElse(memberName); + } + + /** Returns whether this reference explicitly denotes a method. */ + public boolean isMethod() { + return methodSignature.isPresent(); + } + + private static Optional optional(String value) { + return value.isEmpty() ? Optional.empty() : Optional.of(value); + } + + private static boolean isOwner(String owner) { + if (owner.isEmpty()) { + return true; + } + try { + return JavaDSLMill.parser().parse_StringMCType(owner).isPresent(); + } catch (IOException | RuntimeException ignored) { + return false; + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterParam.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterParam.java index 5373ce1d..1efe6059 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterParam.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterParam.java @@ -1,13 +1,26 @@ package de.monticore.codeAdaption.utils; +/** Configures matcher precedence and the policy for Java elements that no strategy matches. */ public enum AdapterParam { + /** Enables convention-based matching of equal Java and reference-CD names. */ NAME_MATCHING, + /** Enables matching when a Java identifier contains a reference-CD element name. */ INFIX_MATCHING, + /** Enables explicit matching through {@link Adapt} metadata. */ ANNOTATION_MATCHING, + /** + * Accepts an otherwise unmatched Java type instead of reporting a validation error. + * + *

The type has no reference-CD incarnation to adapt and is therefore excluded from + * mapping-specific adapted output. Use an explicit {@code @Adapt(ignore = true)} annotation when + * an intentionally unchanged reference type must remain in that output. + */ IGNORE_NON_MATCHED_TYPE, + /** Leaves an otherwise unmatched local variable or parameter unchanged. */ IGNORE_NON_MATCHED_VAR, + /** Leaves an otherwise unmatched field, method, or supertype declaration unchanged. */ IGNORE_NON_MATCHED_TYPE_MEMBER } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterUtils.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterUtils.java index 317df905..257e97e8 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterUtils.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterUtils.java @@ -1,45 +1,124 @@ package de.monticore.codeAdaption.utils; -import static de.monticore.codeAdaption.utils.JavaLoader.print; - import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.se_rwth.commons.logging.Log; import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; import de.monticore.java.javadsl.JavaDSLMill; import de.monticore.java.javadsl._ast.*; import de.monticore.java.javadsl._visitor.JavaDSLTraverser; import de.monticore.javalight._ast.ASTMethodDeclaration; -import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.types.mcbasictypes._ast.ASTMCType; import de.monticore.symbols.oosymbols._symboltable.FieldSymbol; import de.monticore.symboltable.ISymbol; import de.se_rwth.commons.SourcePosition; import java.io.File; import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class AdapterUtils { public static Set getAllCDTypes(ASTCDCompilationUnit cd) { - Set res = new LinkedHashSet<>(); - res.addAll(cd.getCDDefinition().getCDClassesList()); - res.addAll(cd.getCDDefinition().getCDInterfacesList()); - res.addAll(cd.getCDDefinition().getCDEnumsList()); - return res; + return new LinkedHashSet<>(CDModelIndex.of(cd).types()); } public static Optional resolveCDSymbol(String name, ASTCDCompilationUnit refCD) { - List symbol = refCD.getEnclosingScope().resolveFieldMany(name); - if (!symbol.isEmpty()) { - return Optional.of(symbol.iterator().next()); + Optional parsed = AdaptReference.parse(name); + if (parsed.isEmpty() || refCD == null) { + return Optional.empty(); } - return refCD.getEnclosingScope().resolveCDType(name).map(s -> (ISymbol) s).stream().findAny(); + AdaptReference reference = parsed.get(); + String n = reference.memberName(); + CDModelIndex index = CDModelIndex.of(refCD); + Log.debug("AdapterUtils.resolveCDSymbol: resolving '" + name + "'", "AdapterUtils"); + + if (reference.owner().isPresent()) { + String typeName = reference.owner().get(); + String memberName = reference.memberName(); + Log.debug("AdapterUtils.resolveCDSymbol: qualified ref type='" + typeName + "' member='" + memberName + "'", "AdapterUtils"); + + if (reference.isMethod()) { + return index.method(typeName, reference.methodSignature().orElseThrow()) + .map(ASTCDMethod::getSymbol) + .map(symbol -> (ISymbol) symbol); + } + Optional attribute = + index.attribute(typeName, memberName) + .map(ASTCDAttribute::getSymbol) + .map(symbol -> (ISymbol) symbol); + if (attribute.isPresent()) { + Log.debug("AdapterUtils.resolveCDSymbol: resolved to attribute '" + memberName + "' in type '" + typeName + "'", "AdapterUtils"); + return attribute; + } + List methods = index.methods(typeName, memberName); + Optional method = + methods.size() == 1 + ? Optional.of(methods.get(0).getSymbol()) + : Optional.empty(); + if (method.isPresent()) { + Log.debug("AdapterUtils.resolveCDSymbol: resolved to method '" + memberName + "' in type '" + typeName + "'", "AdapterUtils"); + return method; + } + if (methods.size() > 1) { + Log.warn( + "Adapter reference '" + + name + + "' is ambiguous because method '" + + typeName + + "." + + memberName + + "' is overloaded; include a signature-aware mapping"); + return Optional.empty(); + } + } else if (reference.isMethod()) { + List methods = + index.types().stream() + .map(type -> index.method(type.getName(), reference.methodSignature().orElseThrow())) + .flatMap(Optional::stream) + .toList(); + if (methods.size() == 1) { + return Optional.of(methods.get(0).getSymbol()); + } + if (methods.size() > 1) { + Log.warn("Adapter reference '" + name + "' resolves to multiple methods"); + } + return Optional.empty(); + } + + // try resolve as a field in the enclosing scope + List fields = refCD.getEnclosingScope().resolveFieldMany(n); + if (fields.size() == 1) { + Log.debug("AdapterUtils.resolveCDSymbol: resolved to field '" + n + "' in enclosing scope", "AdapterUtils"); + return Optional.of(fields.iterator().next()); + } + if (fields.size() > 1) { + Log.warn("Adapter reference '" + name + "' resolves to multiple fields"); + return Optional.empty(); + } + + // try resolving a top-level CD type by name + Optional tSym = refCD.getEnclosingScope().resolveCDType(n).map(s -> (ISymbol) s).stream().findAny(); + if (tSym.isPresent()) { + Log.debug("AdapterUtils.resolveCDSymbol: resolved to top-level type '" + n + "'", "AdapterUtils"); + } else { + Log.debug("AdapterUtils.resolveCDSymbol: could not resolve '" + name + "' (normalized='" + n + "')", "AdapterUtils"); + } + return tSym; } public static String getFileName(ASTOrdinaryCompilationUnit ast) { return ast.get_SourcePositionStart().getFileName().orElse(""); } + public static String getSimpleFileName(ASTOrdinaryCompilationUnit ast) { + String fullPath = ast.get_SourcePositionStart().getFileName().orElse(""); + if (fullPath.isEmpty()) { + return ""; + } + return new java.io.File(fullPath).getName(); + } + public static String getPosition(SourcePosition pos) { if (pos.getFileName().isPresent()) { String fileName = new File(pos.getFileName().get()).getName(); @@ -48,27 +127,38 @@ public static String getPosition(SourcePosition pos) { return ""; } - /** - * Reads a Java file and removes multi-line and single-line comments. - * - * @param file The Java file from which comments will be removed. - */ - public static void removeComments(File file) { + public static ASTOrdinaryCompilationUnit mergeAsts( + ASTOrdinaryCompilationUnit leftAST, ASTOrdinaryCompilationUnit rightAST) { + return mergeAsts(leftAST, rightAST, false); + } - // remove single line comments - String code = JavaLoader.readFileContent(file).replaceAll("//.*", ""); + /** Merges adapted members into authoritative concrete handwritten code. */ + public static ASTOrdinaryCompilationUnit mergeAstsPreferringLeft( + ASTOrdinaryCompilationUnit leftAST, ASTOrdinaryCompilationUnit rightAST) { + return mergeAsts(leftAST, rightAST, true); + } - // remove multilines comments - Pattern pattern = Pattern.compile("/\\*(?s).*?\\*/"); - Matcher matcher = pattern.matcher(code); - code = matcher.replaceAll(""); + private static ASTOrdinaryCompilationUnit mergeAsts( + ASTOrdinaryCompilationUnit leftAST, + ASTOrdinaryCompilationUnit rightAST, + boolean preferLeftOnConflict) { - // print code - JavaLoader.writeFile(file.toPath(), code); - } + String leftPackage = packageName(leftAST); + String rightPackage = packageName(rightAST); + if (!leftPackage.equals(rightPackage)) { + throw new IllegalArgumentException( + "Cannot merge Java compilation units from different packages: '" + + leftPackage + + "' (" + + getFileName(leftAST) + + ") and '" + + rightPackage + + "' (" + + getFileName(rightAST) + + ")"); + } - public static ASTOrdinaryCompilationUnit mergeAsts( - ASTOrdinaryCompilationUnit leftAST, ASTOrdinaryCompilationUnit rightAST) { + mergeImports(leftAST, rightAST); JavaAstElemCollector lCollector = new JavaAstElemCollector(); JavaDSLTraverser leftTraverser = JavaDSLMill.traverser(); @@ -80,103 +170,284 @@ public static ASTOrdinaryCompilationUnit mergeAsts( rightTraverser.add4JavaDSL(rCollector); rightAST.accept(rightTraverser); - for (ASTTypeDeclaration right : rCollector.getAllTypeDeclarations()) { + // Only compilation-unit declarations participate here. Nested types belong to their enclosing + // declaration and must never be promoted to top-level declarations during a merge. + for (ASTTypeDeclaration right : rightAST.getTypeDeclarationList()) { Optional lType = - lCollector.getAllTypeDeclarations().stream() + leftAST.getTypeDeclarationList().stream() .filter(t -> t.getName().equals(right.getName())) - .findAny(); + .findFirst(); if (lType.isEmpty()) { - leftAST.addTypeDeclaration(right); + leftAST.addTypeDeclaration(right.deepClone()); } else { - leftAST.removeTypeDeclaration(lType.get()); - leftAST.addTypeDeclaration( - mergeTypeDeclaration(lCollector, lType.get(), rCollector, right)); + mergeTypeDeclaration( + lCollector, + lType.get(), + rCollector, + right, + getFileName(leftAST), + getFileName(rightAST), + preferLeftOnConflict); } } return leftAST; } + private static String packageName(ASTOrdinaryCompilationUnit unit) { + return unit.isPresentPackageDeclaration() + ? unit.getPackageDeclaration().getMCQualifiedName().getQName() + : ""; + } + + private static void mergeImports( + ASTOrdinaryCompilationUnit leftAST, ASTOrdinaryCompilationUnit rightAST) { + Set existingImports = new LinkedHashSet<>(); + Map explicitImportsBySimpleName = new LinkedHashMap<>(); + for (ASTImportDeclaration leftImport : leftAST.getImportDeclarationList()) { + registerImport(leftImport, existingImports, explicitImportsBySimpleName); + } + + for (ASTImportDeclaration rightImport : rightAST.getImportDeclarationList()) { + if (registerImport(rightImport, existingImports, explicitImportsBySimpleName)) { + leftAST.addImportDeclaration(rightImport.deepClone()); + } + } + } + + private static boolean registerImport( + ASTImportDeclaration importDeclaration, + Set existingImports, + Map explicitImportsBySimpleName) { + String qualifiedName = importDeclaration.getMCQualifiedName().getQName(); + ImportIdentity identity = + new ImportIdentity(qualifiedName, importDeclaration.isStatic(), importDeclaration.isSTAR()); + if (!existingImports.add(identity)) { + return false; + } + if (identity.star()) { + return true; + } + + String simpleName = JavaSourceNames.simpleName(qualifiedName); + ImportSimpleName key = new ImportSimpleName(simpleName, identity.isStatic()); + String conflict = explicitImportsBySimpleName.putIfAbsent(key, qualifiedName); + if (conflict != null && !conflict.equals(qualifiedName)) { + throw new IllegalStateException( + "Cannot merge imports '" + + conflict + + "' and '" + + qualifiedName + + "' because both use the " + + (identity.isStatic() ? "static member" : "type") + + " name '" + + simpleName + + "'"); + } + return true; + } + + private record ImportIdentity(String qualifiedName, boolean isStatic, boolean star) {} + + private record ImportSimpleName(String name, boolean isStatic) {} + private static ASTTypeDeclaration mergeTypeDeclaration( JavaAstElemCollector lCollector, ASTTypeDeclaration lefType, JavaAstElemCollector rCollector, - ASTTypeDeclaration rightType) { + ASTTypeDeclaration rightType, + String leftSource, + String rightSource, + boolean preferLeftOnConflict) { + + // Get ordered lists of fields and methods from both sides + List lFields = lCollector.getAllFieldDeclarations(lefType); + List rFields = rCollector.getAllFieldDeclarations(rightType); + List lMethods = lCollector.getAllMethodDeclarations(lefType); + List rMethods = rCollector.getAllMethodDeclarations(rightType); + + String typeName = lefType.getName(); + + if (!lefType.getClass().equals(rightType.getClass())) { + if (preferLeftOnConflict) { + return lefType; + } + throw new IllegalStateException( + String.format( + "Cannot merge type '%s': declaration kinds differ in '%s' and '%s'", + typeName, leftSource, rightSource)); + } - // merge methods - for (ASTMethodDeclaration rMeth : rCollector.getAllMethodDeclarations(rightType)) { - Optional lMeth = - lCollector.getAllMethodDeclarations(lefType).stream() - .filter(m -> compare(m, rMeth)) - .findAny(); + mergeTypeRelationships(lefType, rightType); - if (lMeth.isEmpty()) { + // Java overload identity is the method name plus normalized parameter types. A same-name + // method with different parameters is a valid overload and must be retained. + Map leftMethodsBySignature = new LinkedHashMap<>(); + for (ASTMethodDeclaration method : lMethods) { + leftMethodsBySignature.put(getMethodSignature(method), method); + } + for (ASTMethodDeclaration rMeth : rMethods) { + String rSignature = getMethodSignature(rMeth); + ASTMethodDeclaration existingMethod = leftMethodsBySignature.get(rSignature); + + if (existingMethod == null) { if (lefType instanceof ASTClassDeclaration) { - ((ASTClassDeclaration) lefType).getClassBody().addClassBodyDeclaration(rMeth); - } else if (rightType instanceof ASTInterfaceDeclaration) { - ((ASTInterfaceDeclaration) lefType).getInterfaceBody().addInterfaceBodyDeclaration(rMeth); + ((ASTClassDeclaration) lefType) + .getClassBody() + .addClassBodyDeclaration(rMeth.deepClone()); + } else if (lefType instanceof ASTInterfaceDeclaration) { + ((ASTInterfaceDeclaration) lefType) + .getInterfaceBody() + .addInterfaceBodyDeclaration(rMeth.deepClone()); } + leftMethodsBySignature.put(rSignature, rMeth); + } else if (!normalizedReturnType(existingMethod).equals(normalizedReturnType(rMeth)) + && !preferLeftOnConflict) { + throw new IllegalStateException( + String.format( + "Conflicting method '%s' in type '%s': return types differ between '%s' and '%s'", + rSignature, typeName, leftSource, rightSource)); } } - // merge fields - for (ASTFieldDeclaration rField : rCollector.getAllFieldDeclarations(rightType)) { + // A nested type remains a member of its enclosing type. Add missing direct nested types, but + // never expose them through the compilation-unit collector. + if (lefType instanceof ASTClassDeclaration leftClass + && rightType instanceof ASTClassDeclaration rightClass) { + Set leftNestedNames = new LinkedHashSet<>(); + for (var declaration : leftClass.getClassBody().getClassBodyDeclarationList()) { + if (declaration instanceof ASTTypeDeclaration nested) { + leftNestedNames.add(nested.getName()); + } + } + for (var declaration : rightClass.getClassBody().getClassBodyDeclarationList()) { + if (declaration instanceof ASTTypeDeclaration nested + && leftNestedNames.add(nested.getName())) { + leftClass.getClassBody().addClassBodyDeclaration(declaration.deepClone()); + } + } + } - Optional lField = - lCollector.getAllFieldDeclarations(lefType).stream() - .filter( - f -> - f.getVariableDeclarator(0) - .getDeclarator() - .getName() - .equals(rField.getVariableDeclarator(0).getDeclarator().getName())) - .findAny(); + // merge fields - compare by name for conflict detection / deduplication + Map leftFieldsByName = new LinkedHashMap<>(); + for (ASTFieldDeclaration lf : lFields) { + String name = lf.getVariableDeclarator(0).getDeclarator().getName(); + leftFieldsByName.put(name, lf); + } - if (lField.isEmpty()) { + for (ASTFieldDeclaration rf : rFields) { + String rFieldName = rf.getVariableDeclarator(0).getDeclarator().getName(); + if (!leftFieldsByName.containsKey(rFieldName)) { if (lefType instanceof ASTClassDeclaration) { - ((ASTClassDeclaration) lefType).getClassBody().addClassBodyDeclaration(rField); + ((ASTClassDeclaration) lefType) + .getClassBody() + .addClassBodyDeclaration(rf.deepClone()); } + } else if (!normalizedFieldType(leftFieldsByName.get(rFieldName)) + .equals(normalizedFieldType(rf)) + && !preferLeftOnConflict) { + throw new IllegalStateException( + String.format( + "Conflicting field '%s' in type '%s': types differ between '%s' and '%s'", + rFieldName, typeName, leftSource, rightSource)); } } return lefType; } - /*** - * Compare two method (names and types) and return true when the method are the same. - * @param leftMethod the left method. - * @param rightMethod the right method. - * @return true if both method are the same. - */ - protected static boolean compare( - ASTMethodDeclaration leftMethod, ASTMethodDeclaration rightMethod) { - // compare names - if (!leftMethod.getName().equals(rightMethod.getName())) { - return false; + private static void mergeTypeRelationships( + ASTTypeDeclaration leftType, ASTTypeDeclaration rightType) { + if (leftType instanceof ASTClassDeclaration leftClass + && rightType instanceof ASTClassDeclaration rightClass) { + mergeCompletedAbstractModifier(leftClass, rightClass); + if (!leftClass.isPresentSuperClass() && rightClass.isPresentSuperClass()) { + leftClass.setSuperClass(rightClass.getSuperClass().deepClone()); + } + mergeTypes( + leftClass.getImplementedInterfaceList(), rightClass.getImplementedInterfaceList()); + } else if (leftType instanceof ASTInterfaceDeclaration leftInterface + && rightType instanceof ASTInterfaceDeclaration rightInterface) { + mergeTypes( + leftInterface.getExtendedInterfaceList(), rightInterface.getExtendedInterfaceList()); + } else if (leftType instanceof ASTEnumDeclaration leftEnum + && rightType instanceof ASTEnumDeclaration rightEnum) { + mergeTypes(leftEnum.getImplementedInterfaceList(), rightEnum.getImplementedInterfaceList()); + Set constants = + leftEnum.getEnumConstantDeclarationList().stream() + .map(constant -> constant.getName()) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + for (int index = 0; index < rightEnum.getEnumConstantDeclarationList().size(); index++) { + var constant = rightEnum.getEnumConstantDeclaration(index); + if (constants.add(constant.getName())) { + leftEnum + .getEnumConstantDeclarationList() + .add(Math.min(index, leftEnum.sizeEnumConstantDeclarations()), constant.deepClone()); + } + } } + } - // is present parameters ? - if (!leftMethod.getFormalParameters().isPresentFormalParameterListing()) { - return !rightMethod.getFormalParameters().isPresentFormalParameterListing(); + /** + * The concrete source is authoritative for handwritten members, while the adapted declaration's + * abstractness has already been normalized to the final target CD. Preserve that structural + * modifier when the adapted declaration is merged into an existing concrete class. + */ + private static void mergeCompletedAbstractModifier( + ASTClassDeclaration concreteClass, ASTClassDeclaration adaptedClass) { + boolean adaptedIsAbstract = + adaptedClass.getJavaModifierList().stream() + .anyMatch(modifier -> "abstract".equals(JavaLoader.print(modifier).trim())); + boolean concreteIsAbstract = + concreteClass.getJavaModifierList().stream() + .anyMatch(modifier -> "abstract".equals(JavaLoader.print(modifier).trim())); + if (!adaptedIsAbstract) { + concreteClass + .getJavaModifierList() + .removeIf(modifier -> "abstract".equals(JavaLoader.print(modifier).trim())); + return; } + if (concreteIsAbstract) { + return; + } + adaptedClass.getJavaModifierList().stream() + .filter(modifier -> "abstract".equals(JavaLoader.print(modifier).trim())) + .findFirst() + .map(modifier -> modifier.deepClone()) + .ifPresent(concreteClass::addJavaModifier); + } - List leftParams = - leftMethod.getFormalParameters().getFormalParameterListing().getFormalParameterList(); - List rightParams = - rightMethod.getFormalParameters().getFormalParameterListing().getFormalParameterList(); + private static void mergeTypes(List left, List right) { + Set existing = + left.stream() + .map(JavaSourceNames::printNormalizedType) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + right.stream() + .filter(type -> existing.add(JavaSourceNames.printNormalizedType(type))) + .map(ASTMCType::deepClone) + .forEach(left::add); + } - // same number of parameters ? - if (leftParams.size() != rightParams.size()) { - return false; + /** + * Get a method signature string for comparison. + * Format: "methodName(paramType1,paramType2)" + * Uses method name + parameter types (not return type) for comparison. + */ + private static String getMethodSignature(ASTMethodDeclaration method) { + List parameterTypes = new ArrayList<>(); + if (method.getFormalParameters().isPresentFormalParameterListing()) { + method.getFormalParameters().getFormalParameterListing().getFormalParameterList() + .forEach(p -> parameterTypes.add(JavaSourceNames.printNormalizedType(p.getMCType()))); } + return method.getName() + "(" + String.join(",", parameterTypes) + ")"; + } - // parameters have the same type ? - for (int i = 0; i < leftParams.size(); i++) { - if (!print(leftParams.get(i).getMCType()).equals(print(rightParams.get(i).getMCType()))) { - return false; - } - } + private static String normalizedReturnType(ASTMethodDeclaration method) { + return JavaSourceNames.normalizeType(JavaLoader.print(method.getMCReturnType())); + } - return true; + private static String normalizedFieldType(ASTFieldDeclaration field) { + return JavaSourceNames.printNormalizedType(field.getMCType()); } + } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/CDImportProjector.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/CDImportProjector.java new file mode 100644 index 00000000..0c42d5df --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/CDImportProjector.java @@ -0,0 +1,231 @@ +package de.monticore.codeAdaption.utils; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTCompilationUnit; +import de.monticore.java.javadsl._ast.ASTImportDeclaration; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * Projects non-{@code java.lang} imports from reference and concrete class diagrams into + * handwritten Java adapters. + * + *

Explicit imports are projected only into units that use their simple name. This avoids + * creating invalid Java sources merely because unrelated reference and concrete imports have the + * same simple name. CD wildcard imports are retained as wildcards because their exported type set + * cannot be determined from the import declaration alone. + */ +public final class CDImportProjector { + + private CDImportProjector() {} + + /** + * Adds required CD imports to Java compilation units without duplicating existing imports. + * + *

An existing explicit Java import is the authoritative binding for that unit. If a used, + * otherwise-unbound simple name is supplied by multiple distinct explicit CD imports, projection + * fails deterministically instead of creating an uncompilable pair of imports. + * + *

For example, if the reference CD imports {@code reference.Customer} and the concrete CD + * imports {@code concrete.Customer}, a Java unit that uses unqualified {@code Customer} is + * ambiguous and causes an exception. If that unit already imports {@code reference.Customer}, + * the existing Java import wins and no conflicting import is added. A unit that never uses + * {@code Customer} receives neither explicit import. + * + * @param javaUnits handwritten adapter compilation units to update + * @param classDiagrams class diagrams whose imports are projected + */ + public static void project( + Set javaUnits, ASTCDCompilationUnit... classDiagrams) { + Map imports = parseImports(classDiagrams); + if (imports.isEmpty()) { + return; + } + + List> wildcardImports = + imports.entrySet().stream().filter(entry -> entry.getKey().wildcard()).toList(); + Map>> explicitImports = + explicitImportsBySimpleName(imports); + + for (ASTOrdinaryCompilationUnit unit : javaUnits) { + Set existing = new LinkedHashSet<>(); + Map existingExplicitBindings = new LinkedHashMap<>(); + List> importsToAdd = new ArrayList<>(); + for (ASTImportDeclaration importDeclaration : unit.getImportDeclarationList()) { + if (importDeclaration.isStatic()) { + continue; + } + ImportKey key = ImportKey.from(importDeclaration); + existing.add(key); + if (!key.wildcard()) { + existingExplicitBindings.putIfAbsent(key.simpleName(), key.qualifiedName()); + } + } + + for (Map.Entry wildcardImport : wildcardImports) { + queueIfMissing(existing, importsToAdd, wildcardImport); + } + + Set declaredTypeNames = + unit.getTypeDeclarationList().stream() + .map(type -> type.getName()) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + String sourceWithoutImports = sourceWithoutImports(unit); + for (Map.Entry>> candidates : + explicitImports.entrySet()) { + String simpleName = candidates.getKey(); + if (declaredTypeNames.contains(simpleName) + || !usesUnqualifiedName(sourceWithoutImports, simpleName)) { + continue; + } + + String existingBinding = existingExplicitBindings.get(simpleName); + if (existingBinding != null) { + // Handwritten Java already made this binding explicit. Never add a conflicting CD import. + continue; + } + + List> distinctCandidates = + candidates.getValue().stream() + .sorted(Comparator.comparing(entry -> entry.getKey().qualifiedName())) + .toList(); + if (distinctCandidates.size() > 1) { + throw ambiguousImport(simpleName, distinctCandidates); + } + queueIfMissing(existing, importsToAdd, distinctCandidates.get(0)); + } + importsToAdd.forEach(candidate -> unit.addImportDeclaration(candidate.getValue().deepClone())); + } + } + + private static Map>> + explicitImportsBySimpleName(Map imports) { + Map>> bySimpleName = + new LinkedHashMap<>(); + imports.entrySet().stream() + .filter(entry -> !entry.getKey().wildcard()) + .forEach( + entry -> + bySimpleName + .computeIfAbsent(entry.getKey().simpleName(), ignored -> new ArrayList<>()) + .add(entry)); + return bySimpleName; + } + + private static void queueIfMissing( + Set existing, + List> importsToAdd, + Map.Entry candidate) { + if (existing.add(candidate.getKey())) { + importsToAdd.add(candidate); + } + } + + private static IllegalStateException ambiguousImport( + String simpleName, + List> distinctCandidates) { + String qualifiedNames = + distinctCandidates.stream() + .map(entry -> entry.getKey().qualifiedName()) + .collect(java.util.stream.Collectors.joining(", ")); + return new IllegalStateException( + "Ambiguous class-diagram imports for used Java type '" + + simpleName + + "': " + + qualifiedNames); + } + + private static String sourceWithoutImports(ASTOrdinaryCompilationUnit unit) { + ASTOrdinaryCompilationUnit clone = unit.deepClone(); + clone.clearImportDeclarations(); + return JavaLoader.print(clone); + } + + private static boolean usesUnqualifiedName(String source, String simpleName) { + Pattern unqualifiedIdentifier = + Pattern.compile( + "(? parseImports( + ASTCDCompilationUnit... classDiagrams) { + Set importKeys = new LinkedHashSet<>(); + for (ASTCDCompilationUnit classDiagram : classDiagrams) { + if (classDiagram == null) { + continue; + } + classDiagram.getMCImportStatementList().stream() + .map( + statement -> + new ImportKey(statement.getMCQualifiedName().getQName(), statement.isStar())) + .filter(importKey -> !importKey.isJavaLang()) + .forEach(importKeys::add); + } + if (importKeys.isEmpty()) { + return Map.of(); + } + + StringBuilder source = new StringBuilder(); + importKeys.forEach( + importKey -> + source + .append("import ") + .append(importKey.qualifiedName()) + .append(importKey.wildcard() ? ".*" : "") + .append(";\n")); + source.append("class CDImportHolder {}\n"); + try { + Optional parsed = + JavaDSLMill.parser().parse_StringCompilationUnit(source.toString()); + if (parsed.isEmpty() || !(parsed.get() instanceof ASTOrdinaryCompilationUnit unit)) { + throw new IllegalStateException("Could not parse class-diagram imports as Java imports"); + } + Map result = new LinkedHashMap<>(); + unit.getImportDeclarationList() + .forEach(importDeclaration -> result.put(ImportKey.from(importDeclaration), importDeclaration)); + if (!result.keySet().equals(importKeys)) { + throw new IllegalStateException("Java parser changed class-diagram import semantics"); + } + return result; + } catch (IOException e) { + throw new IllegalStateException("Could not parse class-diagram imports as Java imports", e); + } + } + + private record ImportKey(String qualifiedName, boolean wildcard) { + + private ImportKey { + if (qualifiedName == null || qualifiedName.isBlank()) { + throw new IllegalArgumentException("Import qualified name must not be blank"); + } + } + + private static ImportKey from(ASTImportDeclaration importDeclaration) { + return new ImportKey( + importDeclaration.getMCQualifiedName().getQName(), importDeclaration.isSTAR()); + } + + private String simpleName() { + return JavaSourceNames.simpleName(qualifiedName); + } + + private boolean isJavaLang() { + return wildcard + ? "java.lang".equals(qualifiedName) + : qualifiedName.startsWith("java.lang."); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/CDModelIndex.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/CDModelIndex.java new file mode 100644 index 00000000..3710141c --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/CDModelIndex.java @@ -0,0 +1,300 @@ +package de.monticore.codeAdaption.utils; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdassociation._ast.ASTCDAssociation; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDClass; +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdinterfaceandenum._ast.ASTCDEnum; +import de.monticore.cdinterfaceandenum._ast.ASTCDInterface; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * Immutable lookup structure for class-diagram elements and inheritance relationships. + * + *

Named lookups are intentionally based on simple CD type names. Supplying {@code + * shop.Payment} therefore looks up {@code Payment}; this index does not distinguish two types that + * differ only by package. Member-owner lookups use the owning type's simple name, while {@link + * #ownerOf(ASTCDAttribute)} and {@link #ownerOf(ASTCDMethod)} use AST object identity and therefore + * require nodes from this indexed CD. + */ +public final class CDModelIndex { + private final ASTCDCompilationUnit cd; + private final List types; + private final List classes; + private final List interfaces; + private final List enums; + private final List associations; + private final Map typesBySimpleName; + private final Map> attributesByOwner; + private final Map> methodsByOwner; + private final Map attributeOwners; + private final Map methodOwners; + private final Map> directParentsByType; + private final Map> childrenByParent; + private final Map> implementersByInterface; + + private CDModelIndex() { + this.cd = null; + this.types = List.of(); + this.classes = List.of(); + this.interfaces = List.of(); + this.enums = List.of(); + this.associations = List.of(); + this.typesBySimpleName = Map.of(); + this.attributesByOwner = Map.of(); + this.methodsByOwner = Map.of(); + this.attributeOwners = Map.of(); + this.methodOwners = Map.of(); + this.directParentsByType = Map.of(); + this.childrenByParent = Map.of(); + this.implementersByInterface = Map.of(); + } + + private CDModelIndex(ASTCDCompilationUnit cd) { + this.cd = cd; + this.classes = List.copyOf(cd.getCDDefinition().getCDClassesList()); + this.interfaces = List.copyOf(cd.getCDDefinition().getCDInterfacesList()); + this.enums = List.copyOf(cd.getCDDefinition().getCDEnumsList()); + this.associations = List.copyOf(cd.getCDDefinition().getCDAssociationsList()); + + List collectedTypes = new ArrayList<>(); + collectedTypes.addAll(classes); + collectedTypes.addAll(interfaces); + collectedTypes.addAll(enums); + this.types = List.copyOf(collectedTypes); + + Map typeMap = new LinkedHashMap<>(); + Map> attributes = new LinkedHashMap<>(); + Map> methods = new LinkedHashMap<>(); + Map attributeOwnerMap = new IdentityHashMap<>(); + Map methodOwnerMap = new IdentityHashMap<>(); + Map> parents = new LinkedHashMap<>(); + Map> children = new LinkedHashMap<>(); + Map> implementers = new LinkedHashMap<>(); + + for (ASTCDType type : types) { + String typeName = type.getName(); + typeMap.put(typeName, type); + attributes.put(typeName, List.copyOf(type.getCDAttributeList())); + methods.put(typeName, List.copyOf(type.getCDMethodList())); + + for (ASTCDAttribute attribute : type.getCDAttributeList()) { + attributeOwnerMap.put(attribute, type); + } + for (ASTCDMethod method : type.getCDMethodList()) { + methodOwnerMap.put(method, type); + } + + Set directParents = new LinkedHashSet<>(); + CDTypeRelations.firstSuperclassName(type) + .map(JavaSourceNames::simpleName) + .filter(name -> !name.isEmpty()) + .ifPresent(directParents::add); + for (String interfaceName : CDTypeRelations.interfaceNames(type)) { + String simpleName = JavaSourceNames.simpleName(interfaceName); + if (!simpleName.isEmpty()) { + directParents.add(simpleName); + implementers.computeIfAbsent(simpleName, ignored -> new ArrayList<>()).add(type); + } + } + parents.put(typeName, Collections.unmodifiableSet(directParents)); + for (String parent : directParents) { + children.computeIfAbsent(parent, ignored -> new LinkedHashSet<>()).add(typeName); + } + } + + this.typesBySimpleName = Map.copyOf(typeMap); + this.attributesByOwner = copyListMap(attributes); + this.methodsByOwner = copyListMap(methods); + this.attributeOwners = Collections.unmodifiableMap(new IdentityHashMap<>(attributeOwnerMap)); + this.methodOwners = Collections.unmodifiableMap(new IdentityHashMap<>(methodOwnerMap)); + this.directParentsByType = copySetMap(parents); + this.childrenByParent = copySetMap(children); + this.implementersByInterface = copyListMap(implementers); + } + + /** Creates an index, or an empty index when {@code cd} is {@code null}. */ + public static CDModelIndex of(ASTCDCompilationUnit cd) { + if (cd == null) { + return new CDModelIndex(); + } + return new CDModelIndex(cd); + } + + public ASTCDCompilationUnit cd() { + return cd; + } + + public List types() { + return types; + } + + public List classes() { + return classes; + } + + public List interfaces() { + return interfaces; + } + + public List enums() { + return enums; + } + + public List associations() { + return associations; + } + + /** Resolves a type after reducing the supplied name to its simple name. */ + public Optional type(String name) { + return Optional.ofNullable(typesBySimpleName.get(JavaSourceNames.simpleName(name))); + } + + public boolean hasType(String name) { + return type(name).isPresent(); + } + + /** Returns attributes declared directly by the named owner; inherited attributes are excluded. */ + public List attributes(String ownerName) { + return attributesByOwner.getOrDefault(JavaSourceNames.simpleName(ownerName), List.of()); + } + + /** Resolves one directly declared attribute by owner and simple attribute name. */ + public Optional attribute(String ownerName, String attributeName) { + String simpleAttribute = JavaSourceNames.simpleName(attributeName); + return attributes(ownerName).stream() + .filter(attribute -> attribute.getName().equals(simpleAttribute)) + .findFirst(); + } + + /** Returns methods declared directly by the named owner; inherited methods are excluded. */ + public List methods(String ownerName) { + return methodsByOwner.getOrDefault(JavaSourceNames.simpleName(ownerName), List.of()); + } + + /** Returns directly declared overloads having the supplied simple method name. */ + public List methods(String ownerName, String methodName) { + String simpleMethod = JavaSourceNames.simpleName(methodName); + return methods(ownerName).stream() + .filter(method -> method.getName().equals(simpleMethod)) + .toList(); + } + + /** + * Resolves one directly declared method by its normalized {@code name(type,...)} signature. + * + *

For example, {@code method("Order", "update(java.time.Instant)")} does not match a + * zero-argument {@code update()} overload. + */ + public Optional method(String ownerName, String signature) { + String normalizedSignature = signature == null ? "" : signature.trim(); + return methods(ownerName).stream() + .filter(method -> JavaSourceNames.methodSignature(method).equals(normalizedSignature)) + .findFirst(); + } + + public Optional ownerOf(ASTCDAttribute attribute) { + return Optional.ofNullable(attributeOwners.get(attribute)); + } + + public Optional ownerOf(ASTCDMethod method) { + return Optional.ofNullable(methodOwners.get(method)); + } + + /** Returns direct superclass and interface names; the supplied type itself is not included. */ + public Set directParentNames(String typeName) { + return directParentsByType.getOrDefault(JavaSourceNames.simpleName(typeName), Set.of()); + } + + /** Returns every reachable superclass and interface name, excluding the supplied type itself. */ + public Set transitiveParentNames(String typeName) { + Set result = new LinkedHashSet<>(); + ArrayDeque queue = new ArrayDeque<>(directParentNames(typeName)); + while (!queue.isEmpty()) { + String parent = queue.removeFirst(); + if (!result.add(parent)) { + continue; + } + queue.addAll(directParentNames(parent)); + } + return Collections.unmodifiableSet(result); + } + + /** + * Returns whether {@code typeName} has {@code parentName} as a direct or transitive parent. + * Equal type names are not considered a subtype relationship by this method. + */ + public boolean isSubtypeOf(String typeName, String parentName) { + String simpleParent = JavaSourceNames.simpleName(parentName); + return directParentNames(typeName).contains(simpleParent) + || transitiveParentNames(typeName).contains(simpleParent); + } + + /** Returns names of types that directly declare the supplied parent. */ + public Set childNames(String parentName) { + return childrenByParent.getOrDefault(JavaSourceNames.simpleName(parentName), Set.of()); + } + + /** + * Returns types that directly list the supplied interface in their declaration. + * + *

This is a declaration index, not a transitive subtype query. Use {@link #isSubtypeOf} when + * indirect interface implementation must count. + */ + public List implementersOf(String interfaceName) { + return implementersByInterface.getOrDefault(JavaSourceNames.simpleName(interfaceName), List.of()); + } + + /** + * Finds the unique type that directly declares an attribute or method with this simple name. + * Returns empty both when no owner exists and when several types declare that member name. + */ + public Optional ownerOfMemberNamed(String memberName) { + String simpleMember = JavaSourceNames.simpleName(memberName); + ASTCDType owner = null; + for (ASTCDType type : types) { + boolean matches = + attributes(type.getName()).stream().anyMatch(attribute -> attribute.getName().equals(simpleMember)) + || methods(type.getName()).stream().anyMatch(method -> method.getName().equals(simpleMember)); + if (!matches) { + continue; + } + if (owner != null && owner != type) { + return Optional.empty(); + } + owner = type; + } + return Optional.ofNullable(owner); + } + + public Set typeNames() { + return Collections.unmodifiableSet(new LinkedHashSet<>(typesBySimpleName.keySet())); + } + + private static Map> copyListMap(Map> source) { + Map> copy = new LinkedHashMap<>(); + for (Map.Entry> entry : source.entrySet()) { + copy.put(entry.getKey(), List.copyOf(entry.getValue())); + } + return Map.copyOf(copy); + } + + private static Map> copySetMap(Map> source) { + Map> copy = new LinkedHashMap<>(); + for (Map.Entry> entry : source.entrySet()) { + copy.put(entry.getKey(), Set.copyOf(entry.getValue())); + } + return Map.copyOf(copy); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/CDTypeRelations.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/CDTypeRelations.java new file mode 100644 index 00000000..c51e9eae --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/CDTypeRelations.java @@ -0,0 +1,46 @@ +package de.monticore.codeAdaption.utils; + +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.List; +import java.util.Optional; + +/** + * Provides null-safe, consistently rendered access to CD relationships whose generated AST APIs + * vary by type kind or grammar version. + */ +public final class CDTypeRelations { + + private CDTypeRelations() {} + + /** Returns the first declared superclass, preserving the CD's declaration order. */ + public static Optional firstSuperclassName(ASTCDType type) { + if (type != null && !type.getSuperclassList().isEmpty()) { + return Optional.of(printTypeReference(type.getSuperclassList().get(0))); + } + return Optional.empty(); + } + + /** Returns whether the type declares at least one superclass. */ + public static boolean hasSuperclass(ASTCDType type) { + return type != null && !type.getSuperclassList().isEmpty(); + } + + /** Returns whether the type has an explicit {@code abstract} modifier. */ + public static boolean isAbstract(ASTCDType type) { + return type != null && type.getModifier() != null && type.getModifier().isAbstract(); + } + + /** Returns directly declared interface names in declaration order. */ + public static List interfaceNames(ASTCDType type) { + if (type == null) { + return List.of(); + } + return type.getInterfaceList().stream().map(CDTypeRelations::printTypeReference).toList(); + } + + /** Renders a type reference, using {@code Object} for a missing reference. */ + public static String printTypeReference(ASTMCType typeReference) { + return typeReference != null ? JavaLoader.print(typeReference) : "Object"; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Constants.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Constants.java index 73576355..a5989696 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Constants.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Constants.java @@ -1,6 +1,10 @@ package de.monticore.codeAdaption.utils; -public class Constants { +/** Names and placeholder syntax shared by {@link Adapt} parsing and matcher templates. */ +public final class Constants { + + private Constants() {} + public static final String TEMPLATE = "template"; public static final String REFERENCE = "ref"; public static final String ANNOT_NAME = "Adapt"; @@ -13,4 +17,5 @@ public class Constants { public static final String SIMPLE_PLACE_HOLDER = "${}"; public static final String CAP_FIRST_PLACE_HOLDER = "${" + CAP_FIRST + "}"; public static final String UNCAP_FIRST_PLACE_HOLDER = "${" + UNCAP_FIRST + "}"; + public static final String GENERATE_TEMPLATE = "genTemplate"; } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Generator.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Generator.java deleted file mode 100644 index c9a2715c..00000000 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Generator.java +++ /dev/null @@ -1,28 +0,0 @@ -package de.monticore.codeAdaption.utils; - -import de.monticore.CD4CodeTool; -import java.io.File; -import java.nio.file.Path; - -public class Generator { - - public static void generate(File cdFile, Path hwcPath, Path output) { - String[] input = { - "-i", - cdFile.getAbsolutePath(), - "-ct", - "cd2java.CD2Java", - "--gen", - "-hwc", - hwcPath.toString(), - "-o", - output.toString(), - "--fieldfromrole", - "navigable" - }; - CD4CodeTool.main(input); - - // delete hook-points - JavaLoader.readJavaFile(Path.of("target")).forEach(AdapterUtils::removeComments); - } -} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaLoader.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaLoader.java index 05c52bb0..d65474ca 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaLoader.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaLoader.java @@ -1,16 +1,11 @@ package de.monticore.codeAdaption.utils; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import de.monticore.ast.ASTNode; import de.monticore.cd._symboltable.BuiltInTypes; import de.monticore.cd4code.CD4CodeMill; -import de.monticore.cd4code._cocos.CD4CodeCoCoChecker; import de.monticore.cd4code._parser.CD4CodeParser; import de.monticore.cd4code._symboltable.CD4CodeSymbolTableCompleter; import de.monticore.cd4code._symboltable.ICD4CodeArtifactScope; -import de.monticore.cd4code.cocos.CD4CodeCoCosDelegator; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.java.javadsl.JavaDSLMill; import de.monticore.java.javadsl.JavaDSLTool; @@ -23,82 +18,84 @@ import de.monticore.java.javadsl._symboltable.JavaDSLScopesGenitor; import de.monticore.java.javadsl._visitor.JavaDSLTraverser; import de.monticore.prettyprint.IndentPrinter; -import de.monticore.symboltable.ImportStatement; -import de.monticore.types.mcbasictypes.MCBasicTypesMill; import de.monticore.types.mcbasictypes._ast.ASTMCType; -import de.se_rwth.commons.logging.Log; + import java.io.File; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; -import org.junit.jupiter.api.Assertions; +/** + * File-system and parser utilities for the JavaDSL and CD4Code models used during adaptation. + * + *

Loading creates the symbol tables required by the matching and update phases. Semantic + * validation is deliberately owned by the caller: this utility does not select or execute a + * CD4Code CoCo set because different adaptation inputs permit different degrees of + * underspecification. + */ public class JavaLoader { /** - * Parses a class diagram, builds the symbol table, and checks the consistency conditions (CoCos). + * Parses a class diagram and builds the symbol table required for name and type resolution. + * + *

No CD4Code CoCos are executed. Callers that require a particular semantic profile must run + * its checker explicitly after loading. * * @param file The class diagram file to be parsed. It must have a .cd extension. * @return The resulting ASTCDCompilationUnit created from the class diagram. - * @throws AssertionError if the provided file does not have a .cd extension, or if the AST could - * not be created successfully. + * @throws IllegalArgumentException if the provided file is not a readable CD file + * @throws IllegalStateException if parsing fails */ public static ASTCDCompilationUnit loadCD(File file) { // parse the class diagram - assert file.getName().endsWith(".cd"); + requireFileExtension(file, ".cd"); CD4CodeParser cdParser = new CD4CodeParser(); Optional optCdAST = Optional.empty(); try { optCdAST = cdParser.parse(file.getAbsolutePath()); } catch (IOException e) { - System.out.println(e); - // Log.error("It was not possible to parse the class diagram " + file.getAbsolutePath()); + throw new IllegalStateException("Could not read class diagram " + file.getAbsolutePath(), e); + } + if (optCdAST.isEmpty()) { + throw new IllegalStateException("Could not parse class diagram " + file.getAbsolutePath()); } - Assertions.assertTrue(optCdAST.isPresent()); // create symbol table - createCDSymTab(optCdAST.get()); + initializeCDSymbolTable(optCdAST.get()); - // checkCoCos - CD4CodeCoCoChecker cdChecker = new CD4CodeCoCosDelegator().getCheckerForAllCoCos(); - // cdChecker.checkAll(optCdAST.get()); return optCdAST.get(); } + /** + * Parses a CD file with the same symbol-table setup used by {@link #loadCD(File)}, but without + * requiring the diagram name to match the file name. This is used by adaptation fixtures whose + * file names are scenario-oriented. + */ public static ASTCDCompilationUnit parseCD(String cdFile) { try { Optional cd = CD4CodeMill.parser().parseCDCompilationUnit(cdFile); if (cd.isPresent()) { - ICD4CodeArtifactScope as = CD4CodeMill.scopesGenitorDelegator().createFromAST(cd.get()); - as.addImports(new ImportStatement("java.lang.String", true)); - as.addImports(new ImportStatement("java.util", true)); - cd.get().accept(new CD4CodeSymbolTableCompleter(cd.get()).getTraverser()); - + initializeCDSymbolTable(cd.get()); return cd.get(); - } else { - fail("Could not parse CDs."); } - + throw new IllegalStateException("Could not parse class diagram " + cdFile); } catch (IOException e) { - fail(e.getMessage()); + throw new IllegalStateException("Could not read class diagram " + cdFile, e); } - return null; } - private static void createCDSymTab(ASTCDCompilationUnit ast) { + /** Rebuilds the symbol table for a parsed or cloned class-diagram AST. */ + public static void initializeCDSymbolTable(ASTCDCompilationUnit ast) { BuiltInTypes.addBuiltInTypes(CD4CodeMill.globalScope()); ICD4CodeArtifactScope as = CD4CodeMill.scopesGenitorDelegator().createFromAST(ast); - as.addImports(new ImportStatement("java.lang", true)); - as.addImports(new ImportStatement("java.util", true)); - CD4CodeSymbolTableCompleter c = - new CD4CodeSymbolTableCompleter( - ast.getMCImportStatementList(), MCBasicTypesMill.mCQualifiedNameBuilder().build()); + CD4CodeSymbolTableCompleter c = new CD4CodeSymbolTableCompleter(ast); ast.accept(c.getTraverser()); ast.setEnclosingScope(as); } @@ -110,15 +107,21 @@ private static void createCDSymTab(ASTCDCompilationUnit ast) { * @return The resulting ASTOrdinaryCompilationUnit created from the Java file. */ public static ASTOrdinaryCompilationUnit loadJava(File javaFile) { - assertTrue(javaFile.getName().endsWith(".java")); + requireFileExtension(javaFile, ".java"); // parse JavaDSLTool tool = new JavaDSLTool(); Optional ast; ast = Optional.ofNullable(tool.parse(javaFile.getAbsolutePath())); - assertTrue(ast.isPresent()); - assertTrue(ast.get() instanceof ASTOrdinaryCompilationUnit); + if (ast.isEmpty()) { + throw new IllegalStateException("Could not parse Java source " + javaFile.getAbsolutePath()); + } + if (!(ast.get() instanceof ASTOrdinaryCompilationUnit)) { + throw new IllegalStateException( + "Expected an ordinary Java compilation unit in " + javaFile.getAbsolutePath()); + } + ASTOrdinaryCompilationUnit ordinaryCompilationUnit = (ASTOrdinaryCompilationUnit) ast.get(); // create symbol table IJavaDSLGlobalScope globalScope = JavaDSLMill.globalScope(); @@ -128,10 +131,10 @@ public static ASTOrdinaryCompilationUnit loadJava(File javaFile) { traverser.add4JavaDSL(genitor); genitor.putOnStack(globalScope); - IJavaDSLArtifactScope artifactScope = genitor.createFromAST(ast.get()); + IJavaDSLArtifactScope artifactScope = genitor.createFromAST(ordinaryCompilationUnit); globalScope.addSubScope(artifactScope); - return (ASTOrdinaryCompilationUnit) ast.get(); + return ordinaryCompilationUnit; } /** @@ -154,9 +157,12 @@ public static String print(ASTMCType type) { public static void writeFile(Path path, String content) { try { - FileUtils.writeStringToFile(path.toFile(), content, Charset.defaultCharset(), false); + if (path.getParent() != null) { + Files.createDirectories(path.getParent()); + } + Files.writeString(path, content, StandardCharsets.UTF_8); } catch (IOException e) { - Log.error("Exception occur when writing the file " + path); + throw new IllegalStateException("Could not write file " + path, e); } } @@ -165,11 +171,13 @@ public static void writeFile(Path path, String content) { * * @param directoryPath The root directory to read. * @return A set of Java files represented as ASTOrdinaryCompilationUnit. - */ + */ public static Set readJavaCode(Path directoryPath) { + // Clear stale artifact scopes before loading a new source batch. + JavaDSLMill.globalScope().clear(); Set res = new LinkedHashSet<>(); readJavaCode(directoryPath, res); - return res.stream().map(JavaLoader::loadJava).collect(Collectors.toSet()); + return res.stream().map(JavaLoader::loadJava).collect(Collectors.toCollection(LinkedHashSet::new)); } /** @@ -185,47 +193,100 @@ public static Set readJavaFile(Path directoryPath) { } private static void readJavaCode(Path directoryPath, Set res) { - File directory = directoryPath.toFile(); - File[] files = directory.listFiles(); - - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - readJavaCode(file.toPath(), res); - } else if (file.isFile() && file.getName().endsWith(".java")) { - res.add(file); - } - } + Path normalized = directoryPath.toAbsolutePath().normalize(); + if (!Files.exists(normalized)) { + throw new IllegalArgumentException("Java source directory does not exist: " + normalized); + } + if (!Files.isDirectory(normalized)) { + throw new IllegalArgumentException("Java source path is not a directory: " + normalized); + } + try (var paths = Files.walk(normalized)) { + paths.filter(Files::isRegularFile) + .filter(path -> path.getFileName().toString().endsWith(".java")) + .sorted(Comparator.comparing(Path::toString)) + .map(Path::toFile) + .forEach(res::add); + } catch (IOException e) { + throw new IllegalStateException("Could not read Java source directory " + normalized, e); } } public static String readFileContent(File file) { - byte[] bytes = new byte[0]; try { - bytes = Files.readAllBytes(Path.of(file.getAbsolutePath())); + return Files.readString(file.toPath(), StandardCharsets.UTF_8); } catch (IOException e) { - Log.error("It was not possible to read the file " + file.getAbsolutePath()); + throw new IllegalStateException("Could not read file " + file.getAbsolutePath(), e); } - return new String(bytes); } + /** + * Pretty-prints Java ASTs into {@code codePath}, preserving package directories when present. + */ public static void printAST(Set asts, Path codePath) { for (ASTOrdinaryCompilationUnit ast : asts) { - File sourceFile = - new File(ast.get_SourcePositionStart().getFileName().orElse(codePath.toString())); + Path targetPath = outputPathFor(ast, codePath); + JavaDSLFullPrettyPrinter prettyPrinter = new JavaDSLFullPrettyPrinter(new IndentPrinter()); String output = prettyPrinter.prettyprint(ast); - JavaLoader.writeFile(sourceFile.toPath(), output); + JavaLoader.writeFile(targetPath, output); + } + } + + private static Path outputPathFor(ASTOrdinaryCompilationUnit ast, Path codePath) { + String fileName = primaryTypeFileName(ast).orElseGet(() -> sourceFileName(ast).orElse("Unknown.java")); + if (ast.isPresentPackageDeclaration()) { + Path packagePath = + Path.of( + ast.getPackageDeclaration() + .getMCQualifiedName() + .getQName() + .replace('.', File.separatorChar)); + return codePath.resolve(packagePath).resolve(fileName); } + return codePath.resolve(sourceFileName(ast).orElse(fileName)); + } + + private static Optional primaryTypeFileName(ASTOrdinaryCompilationUnit ast) { + return ast.getTypeDeclarationList().stream() + .findFirst() + .map(type -> type.getName() + ".java"); + } + + private static Optional sourceFileName(ASTOrdinaryCompilationUnit ast) { + return ast.get_SourcePositionStart() + .getFileName() + .flatMap( + fileName -> { + try { + return Optional.of(Path.of(fileName).getFileName().toString()); + } catch (InvalidPathException e) { + return Optional.empty(); + } + }); } + /** + * Deletes an output directory before adaptation writes new generated code. + */ public static void removeDirectory(Path path) { + Path normalized = path.toAbsolutePath().normalize(); + if (normalized.getParent() == null) { + throw new IllegalArgumentException("Refusing to delete filesystem root: " + normalized); + } try { - // Delete the directory and its contents - FileUtils.deleteDirectory(new File(path.toString())); - ; + FileUtils.deleteDirectory(normalized.toFile()); } catch (IOException e) { - Log.error("Failed to delete directory: " + e.getMessage()); + throw new IllegalStateException("Failed to delete directory " + normalized, e); + } + } + + private static void requireFileExtension(File file, String extension) { + Objects.requireNonNull(file, "file"); + if (!file.getName().endsWith(extension)) { + throw new IllegalArgumentException("Expected a " + extension + " file: " + file); + } + if (!file.isFile()) { + throw new IllegalArgumentException("File does not exist or is not a regular file: " + file); } } } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaMethodSignatures.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaMethodSignatures.java new file mode 100644 index 00000000..d7da458a --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaMethodSignatures.java @@ -0,0 +1,97 @@ +package de.monticore.codeAdaption.utils; + +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTMCBasicGenericType; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.monticore.types.mccollectiontypes._ast.ASTMCTypeArgument; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * Creates method lookup keys by parsing Java type syntax instead of manually splitting nested + * generic parameter lists. + */ +public final class JavaMethodSignatures { + + private static final String PARAMETER_CONTAINER = "__MethodParameters"; + + private JavaMethodSignatures() {} + + /** + * Parses and normalizes a complete method signature. + * + *

For example, {@code + * update(java.util.Map>,int[],long)} becomes {@code + * update(Map>,int[],long)}. + * + * @param signature method name followed by a parameter-type list + * @return the normalized signature, or empty when the input is not a complete valid signature + */ + public static Optional parseNormalized(String signature) { + if (signature == null) { + return Optional.empty(); + } + String normalized = signature.trim(); + int open = normalized.indexOf('('); + int close = normalized.lastIndexOf(')'); + if (open < 1 + || close < open + || close != normalized.length() - 1 + || normalized.indexOf('(', open + 1) >= 0) { + return Optional.empty(); + } + + String methodName = normalized.substring(0, open).trim(); + if (!isMethodName(methodName)) { + return Optional.empty(); + } + String parameters = normalized.substring(open + 1, close).trim(); + if (parameters.isEmpty()) { + return Optional.of(methodName + "()"); + } + return parseParameterTypes(parameters) + .map(types -> methodName + "(" + String.join(",", types) + ")"); + } + + private static boolean isMethodName(String name) { + try { + return JavaDSLMill.parser().parse_StringMethodDeclaration("void " + name + "() {}").isPresent(); + } catch (IOException | RuntimeException ignored) { + return false; + } + } + + /** + * Parses a comma-separated parameter list by embedding it as the type arguments of a synthetic + * generic type. This lets the JavaDSL grammar, rather than string splitting, distinguish commas + * between parameters from commas inside nested generic types. + * + *

The arbitrary container name is parsed by JavaDSL as {@link ASTMCBasicGenericType}; its type + * arguments are the original method parameter types. + */ + private static Optional> parseParameterTypes(String parameters) { + try { + Optional parsed = + JavaDSLMill.parser().parse_StringMCType(PARAMETER_CONTAINER + "<" + parameters + ">"); + if (parsed.isEmpty()) { + return Optional.empty(); + } + if (!(parsed.get() instanceof ASTMCBasicGenericType basicGeneric)) { + return Optional.empty(); + } + List arguments = basicGeneric.getMCTypeArgumentList(); + List types = new ArrayList<>(); + for (ASTMCTypeArgument argument : arguments) { + if (argument.getMCTypeOpt().isEmpty()) { + return Optional.empty(); + } + types.add(JavaSourceNames.printNormalizedType(argument.getMCTypeOpt().get())); + } + return Optional.of(List.copyOf(types)); + } catch (IOException | RuntimeException ignored) { + return Optional.empty(); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaSourceNames.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaSourceNames.java new file mode 100644 index 00000000..a20a4f73 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaSourceNames.java @@ -0,0 +1,455 @@ +package de.monticore.codeAdaption.utils; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._ast.ASTCDParameter; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.types.mcarraytypes._ast.ASTMCArrayType; +import de.monticore.types.mcbasictypes._ast.ASTMCPrimitiveType; +import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.monticore.types.mcbasictypes._ast.ASTMCReturnType; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; +import de.monticore.types.mccollectiontypes._ast.ASTMCTypeArgument; +import de.monticore.types.mcfullgenerictypes._ast.ASTMCWildcardTypeArgument; +import java.io.IOException; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +/** + * Shared Java/CD naming and type operations with parser-first handling of qualified names, + * generics, arrays, primitives, wildcards, and the CD placeholder type {@code any}. + */ +public final class JavaSourceNames { + + private JavaSourceNames() {} + + /** + * Extracts the simple leaf name from a Java type, qualified name, or method-like value. + * + * @return an empty string for {@code null}; otherwise the parser-derived or conservative fallback + * simple name + */ + public static String simpleName(String name) { + if (name == null) { + return ""; + } + String trimmed = beforeParameterList(name.trim()); + if (trimmed.isEmpty()) { + return ""; + } + return parseTypeKey(trimmed) + .map(TypeKey::simpleName) + .orElseGet(() -> fallbackSimpleName(trimmed)); + } + + /** Alias for {@link #simpleName(String)} used when the input is known to be a type. */ + public static String simpleTypeName(String typeName) { + return simpleName(typeName); + } + + /** + * Normalizes a printed Java/CD type to simple type names while preserving generic and array + * structure and translating {@code any} to {@code Object}. + */ + public static String normalizeType(String type) { + String normalized = type == null ? "" : type.trim(); + if (normalized.isBlank()) { + return "Object"; + } + String rendered = parseTypeKey(normalized) + .map(TypeKey::normalized) + .orElseGet(() -> fallbackNormalize(normalized)); + return rendered; + } + + /** Renders and normalizes a non-void MontiCore type AST. */ + public static String printNormalizedType(ASTMCType type) { + return TypeKey.from(type).normalized(); + } + + /** Renders the normalized type of a CD attribute. */ + public static String printNormalizedFieldType(ASTCDAttribute attribute) { + return printNormalizedType(attribute.getMCType()); + } + + /** Renders the normalized return type, including {@code void}, of a CD method. */ + public static String printNormalizedReturnType(ASTCDMethod method) { + return TypeKey.from(method.getMCReturnType()).normalized(); + } + + /** Returns an owner-independent {@code name(type,...)} lookup key for a CD method. */ + public static String methodSignature(ASTCDMethod method) { + List parameters = new ArrayList<>(); + for (ASTCDParameter parameter : method.getCDParameterList()) { + parameters.add(printNormalizedType(parameter.getMCType())); + } + return method.getName() + "(" + String.join(",", parameters) + ")"; + } + + /** Uppercases the first character without changing the remainder. */ + public static String capitalize(String value) { + if (value == null || value.isEmpty()) { + return value; + } + return Character.toUpperCase(value.charAt(0)) + value.substring(1); + } + + /** Lowercases the first character without changing the remainder. */ + public static String uncapitalize(String value) { + if (value == null || value.isEmpty()) { + return value; + } + return Character.toLowerCase(value.charAt(0)) + value.substring(1); + } + + /** Returns the number of path segments in a normalized source file name. */ + public static int pathDepth(String fileName) { + if (fileName == null || fileName.isBlank()) { + return 0; + } + try { + return Path.of(fileName).getNameCount(); + } catch (InvalidPathException ignored) { + return fileName.replace('\\', '/').split("/").length; + } + } + + /** + * Rewrites simple type-name leaves inside a printed Java type while preserving parsed generic and + * array structure. The mapper receives each leaf simple name and can return a replacement. + */ + public static String replaceSimpleTypeNames( + String rawType, Function> replacementForSimpleName) { + if (rawType == null || rawType.isEmpty()) { + return rawType; + } + Optional parsed = parseTypeKey(rawType.trim()); + if (parsed.isEmpty()) { + Optional replacement = + replacementForSimpleName.apply(fallbackSimpleName(rawType.trim())); + return replacement.orElse(rawType); + } + RewriteResult rewritten = parsed.get().rewrite(replacementForSimpleName); + return rewritten.changed() ? rewritten.type().render(false, true, false) : rawType; + } + + /** Describes one named leaf in a parsed Java type without discarding qualification. */ + public record TypeReferenceName(String originalName, String simpleName, boolean qualified) {} + + /** + * Extracts named leaves from a type, including nested generic arguments and wildcard bounds. + * Arrays retain the identity of their component type. + */ + public static List typeReferences(String rawType) { + if (rawType == null || rawType.isBlank()) { + return List.of(); + } + Optional parsed = parseTypeKey(rawType.trim()); + if (parsed.isEmpty()) { + String fallback = fallbackSimpleName(rawType); + return fallback.isBlank() + ? List.of() + : List.of(new TypeReferenceName(rawType.trim(), fallback, rawType.contains("."))); + } + List references = new ArrayList<>(); + parsed.get().collectReferences(references); + return List.copyOf(references); + } + + private static Optional parseTypeKey(String rawType) { + try { + Optional returnType = + JavaDSLMill.parser().parse_StringMCReturnType(rawType); + if (returnType.isPresent()) { + return Optional.of(TypeKey.from(returnType.get())); + } + } catch (IOException | RuntimeException ignored) { + // Fall through to the Java type parser. + } + + try { + Optional type = JavaDSLMill.parser().parse_StringMCType(rawType); + if (type.isPresent()) { + return Optional.of(TypeKey.from(type.get())); + } + } catch (IOException | RuntimeException ignored) { + } + + return Optional.empty(); + } + + private static String beforeParameterList(String value) { + int paren = value.indexOf('('); + return paren >= 0 ? value.substring(0, paren).trim() : value; + } + + private static String fallbackNormalize(String value) { + String compact = value.replace(" ", ""); + if ("any".equals(compact)) { + return "Object"; + } + return fallbackSimpleName(compact); + } + + /** + * Boxes primitive generic type arguments through the type parser while preserving malformed input + * unchanged. + */ + public static String boxPrimitiveTypeArguments(String rendered) { + return parseTypeKey(rendered == null ? "" : rendered.trim()) + .map(TypeKey::normalized) + .orElse(rendered); + } + + private static String fallbackSimpleName(String value) { + // This path is deliberately conservative and runs only when JavaDSL cannot parse the input. + String simple = value.trim(); + while (simple.endsWith("[]")) { + simple = simple.substring(0, simple.length() - 2).trim(); + } + int generic = simple.indexOf('<'); + if (generic >= 0) { + simple = simple.substring(0, generic).trim(); + } + int dot = simple.lastIndexOf('.'); + return dot < 0 ? simple : simple.substring(dot + 1).trim(); + } + + private record TypeKey(String name, List arguments, int arrayDimensions) { + + private static TypeKey from(ASTMCReturnType returnType) { + if (returnType.isPresentMCVoidType()) { + return named("void"); + } + return from(returnType.getMCType()); + } + + private static TypeKey from(ASTMCType type) { + if (type instanceof ASTMCArrayType arrayType) { + return from(arrayType.getMCType()).withAdditionalArrays(arrayType.getDimensions()); + } + if (type instanceof ASTMCPrimitiveType primitiveType) { + return named(primitiveType.printType()); + } + if (type instanceof de.monticore.java.javadsl._ast.ASTMCBasicGenericType basicGenericType) { + return new TypeKey( + basicGenericType.getAnnotatedNameList().stream() + .map(de.monticore.java.javadsl._ast.ASTAnnotatedName::getName) + .reduce((left, right) -> left + "." + right) + .orElse(""), + basicGenericType.getMCTypeArgumentList().stream() + .map(TypeArgumentKey::from) + .toList(), + 0); + } + if (type instanceof ASTMCGenericType genericType) { + return new TypeKey( + String.join(".", genericType.getNameList()), + genericType.getMCTypeArgumentList().stream() + .map(TypeArgumentKey::from) + .toList(), + 0); + } + if (type instanceof ASTMCQualifiedType qualifiedType) { + return named(qualifiedType.getMCQualifiedName().getQName()); + } + return named(type.printType()); + } + + private static TypeKey named(String name) { + return new TypeKey(name, List.of(), 0); + } + + private TypeKey withAdditionalArrays(int additionalArrayDimensions) { + return new TypeKey(name, arguments, arrayDimensions + additionalArrayDimensions); + } + + private String simpleName() { + return normalizeLeafName(name); + } + + private String normalized() { + return render(true, false, false); + } + + private String render(boolean normalizeNames, boolean spaced, boolean boxLeaf) { + String leafName = normalizeNames ? normalizeLeafName(name) : name; + if (boxLeaf) { + leafName = boxedPrimitiveName(leafName); + } + StringBuilder result = new StringBuilder(leafName); + if (!arguments.isEmpty()) { + String delimiter = spaced ? ", " : ","; + result.append("<"); + for (int i = 0; i < arguments.size(); i++) { + if (i > 0) { + result.append(delimiter); + } + result.append(arguments.get(i).render(normalizeNames, spaced)); + } + result.append(">"); + } + result.append("[]".repeat(arrayDimensions)); + return result.toString(); + } + + private RewriteResult rewrite(Function> replacementForSimpleName) { + boolean changed = false; + String rewrittenName = name; + Optional replacement = replacementForSimpleName.apply(simpleName()); + if (replacement.isPresent()) { + rewrittenName = replacement.get(); + changed = true; + } + + List rewrittenArguments = new ArrayList<>(); + for (TypeArgumentKey argument : arguments) { + TypeArgumentRewrite rewritten = argument.rewrite(replacementForSimpleName); + rewrittenArguments.add(rewritten.argument()); + changed |= rewritten.changed(); + } + return new RewriteResult( + new TypeKey(rewrittenName, List.copyOf(rewrittenArguments), arrayDimensions), changed); + } + + private void collectReferences(List references) { + if (!name.isBlank() && !isPrimitiveOrVoid(name)) { + references.add(new TypeReferenceName(name, simpleName(), name.contains("."))); + } + for (TypeArgumentKey argument : arguments) { + argument.collectReferences(references); + } + } + + private static boolean isPrimitiveOrVoid(String value) { + return switch (value) { + case "boolean", "byte", "short", "int", "long", "float", "double", "char", "void" -> + true; + default -> false; + }; + } + + private static String boxedPrimitiveName(String value) { + return switch (value) { + case "boolean" -> "Boolean"; + case "byte" -> "Byte"; + case "short" -> "Short"; + case "int" -> "Integer"; + case "long" -> "Long"; + case "float" -> "Float"; + case "double" -> "Double"; + case "char" -> "Character"; + default -> value; + }; + } + + private static String normalizeLeafName(String value) { + if (value == null || value.isBlank() || "any".equals(value)) { + return "Object"; + } + int dot = value.lastIndexOf('.'); + String simple = dot < 0 ? value : value.substring(dot + 1); + return "any".equals(simple) ? "Object" : simple; + } + } + + private interface TypeArgumentKey { + static TypeArgumentKey from(ASTMCTypeArgument argument) { + if (argument instanceof ASTMCWildcardTypeArgument wildcard) { + if (wildcard.isPresentUpperBound()) { + return new WildcardTypeArgument(Optional.of(TypeKey.from(wildcard.getUpperBound())), true); + } + if (wildcard.isPresentLowerBound()) { + return new WildcardTypeArgument( + Optional.of(TypeKey.from(wildcard.getLowerBound())), false); + } + return new WildcardTypeArgument(Optional.empty(), true); + } + return argument + .getMCTypeOpt() + .map(type -> new ConcreteTypeArgument(TypeKey.from(type))) + .orElseGet(() -> new UnknownTypeArgument(argument.printType())); + } + + String render(boolean normalizeNames, boolean spaced); + + TypeArgumentRewrite rewrite(Function> replacementForSimpleName); + + void collectReferences(List references); + } + + private record ConcreteTypeArgument(TypeKey type) implements TypeArgumentKey { + @Override + public String render(boolean normalizeNames, boolean spaced) { + return type.render(normalizeNames, spaced, true); + } + + @Override + public TypeArgumentRewrite rewrite( + Function> replacementForSimpleName) { + RewriteResult rewritten = type.rewrite(replacementForSimpleName); + return new TypeArgumentRewrite(new ConcreteTypeArgument(rewritten.type()), rewritten.changed()); + } + + @Override + public void collectReferences(List references) { + type.collectReferences(references); + } + } + + private record WildcardTypeArgument(Optional bound, boolean upper) + implements TypeArgumentKey { + @Override + public String render(boolean normalizeNames, boolean spaced) { + if (bound.isEmpty()) { + return "?"; + } + String separator = spaced ? (upper ? " extends " : " super ") : (upper ? "extends" : "super"); + return "?" + separator + bound.get().render(normalizeNames, spaced, true); + } + + @Override + public TypeArgumentRewrite rewrite( + Function> replacementForSimpleName) { + if (bound.isEmpty()) { + return new TypeArgumentRewrite(this, false); + } + RewriteResult rewritten = bound.get().rewrite(replacementForSimpleName); + return new TypeArgumentRewrite( + new WildcardTypeArgument(Optional.of(rewritten.type()), upper), rewritten.changed()); + } + + @Override + public void collectReferences(List references) { + bound.ifPresent(type -> type.collectReferences(references)); + } + } + + private record UnknownTypeArgument(String raw) implements TypeArgumentKey { + @Override + public String render(boolean normalizeNames, boolean spaced) { + return normalizeNames ? normalizeType(raw) : raw; + } + + @Override + public TypeArgumentRewrite rewrite( + Function> replacementForSimpleName) { + String rewritten = replaceSimpleTypeNames(raw, replacementForSimpleName); + return new TypeArgumentRewrite(new UnknownTypeArgument(rewritten), !rewritten.equals(raw)); + } + + @Override + public void collectReferences(List references) { + references.addAll(typeReferences(raw)); + } + } + + private record RewriteResult(TypeKey type, boolean changed) {} + + private record TypeArgumentRewrite(TypeArgumentKey argument, boolean changed) {} +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaSourcePostProcessor.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaSourcePostProcessor.java new file mode 100644 index 00000000..d298370b --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaSourcePostProcessor.java @@ -0,0 +1,337 @@ +package de.monticore.codeAdaption.utils; + +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTCompilationUnit; +import de.monticore.java.javadsl._ast.ASTImportDeclaration; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.se_rwth.commons.logging.Log; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** Import cleanup for generated Java sources, backed by JavaDSL source positions. */ +public final class JavaSourcePostProcessor { + + private JavaSourcePostProcessor() {} + + public static void processDirectory(Path codePath) throws IOException { + List javaFiles; + try (var paths = Files.walk(codePath)) { + javaFiles = + paths + .filter(Files::isRegularFile) + .filter(path -> path.toString().endsWith(".java")) + .sorted() + .toList(); + } + + Map states = new LinkedHashMap<>(); + for (Path javaFile : javaFiles) { + String content = Files.readString(javaFile, StandardCharsets.UTF_8); + SourceState state = removeInvalidImports(content); + states.put(javaFile, state); + } + + for (Path javaFile : javaFiles) { + SourceState state = states.get(javaFile); + String processed = process(state.content(), javaFile.getFileName().toString()); + String original = Files.readString(javaFile, StandardCharsets.UTF_8); + if (!processed.equals(original)) { + Files.writeString(javaFile, processed, StandardCharsets.UTF_8); + } + } + } + + public static String process(String content) { + return process(content, primaryTypeFileName(content)); + } + + public static String process(String content, String fileName) { + content = normalizeJavaSource(content); + Optional ast = parseOrdinaryCompilationUnit(content); + if (ast.isEmpty()) { + Log.warn("Could not parse generated Java source for structured import cleanup."); + return content; + } + + List invalidImports = knownInvalidImports(ast.get()); + if (invalidImports.isEmpty()) { + return content; + } + return applyImportEdits(content, invalidImports, ast.get()); + } + + private static SourceState removeInvalidImports(String content) { + content = normalizeJavaSource(content); + Optional ast = parseOrdinaryCompilationUnit(content); + if (ast.isEmpty()) { + Log.warn("Could not parse generated Java source before import cleanup."); + return new SourceState(content); + } + + List invalidImports = knownInvalidImports(ast.get()); + String cleaned = applyImportEdits(content, invalidImports, ast.get()); + return new SourceState(cleaned); + } + + private static Optional parseOrdinaryCompilationUnit( + String content) { + try { + Optional ast = JavaDSLMill.parser().parse_StringCompilationUnit(content); + return ast.filter(ASTOrdinaryCompilationUnit.class::isInstance) + .map(ASTOrdinaryCompilationUnit.class::cast); + } catch (IOException | RuntimeException e) { + Log.debug( + "JavaDSL could not parse generated source: " + e.getMessage(), + "JavaSourcePostProcessor"); + return Optional.empty(); + } + } + + private static String normalizeJavaSource(String content) { + return removeParameterizedImports(content); + } + + private static String removeParameterizedImports(String content) { + StringBuilder cleaned = new StringBuilder(content.length()); + LexicalState state = LexicalState.NORMAL; + int lineStart = 0; + while (lineStart < content.length()) { + int lineEnd = lineStart; + while (lineEnd < content.length() + && content.charAt(lineEnd) != '\r' + && content.charAt(lineEnd) != '\n') { + lineEnd++; + } + int nextLine = lineEnd; + if (nextLine < content.length() && content.charAt(nextLine) == '\r') { + nextLine++; + } + if (nextLine < content.length() && content.charAt(nextLine) == '\n') { + nextLine++; + } + + String line = content.substring(lineStart, lineEnd); + if (!(state == LexicalState.NORMAL && isParameterizedImportLine(line))) { + cleaned.append(content, lineStart, nextLine); + } + state = advanceLexicalState(content, lineStart, nextLine, state); + lineStart = nextLine; + } + return cleaned.toString(); + } + + private static boolean isParameterizedImportLine(String line) { + String trimmed = line.trim(); + return trimmed.startsWith("import ") + && !trimmed.startsWith("import static ") + && trimmed.endsWith(";") + && trimmed.substring("import ".length(), trimmed.length() - 1).contains("<"); + } + + private static LexicalState advanceLexicalState( + String content, int start, int end, LexicalState initialState) { + LexicalState state = initialState; + for (int index = start; index < end; index++) { + char current = content.charAt(index); + char next = index + 1 < end ? content.charAt(index + 1) : '\0'; + switch (state) { + case NORMAL -> { + if (current == '/' && next == '/') { + state = LexicalState.LINE_COMMENT; + index++; + } else if (current == '/' && next == '*') { + state = LexicalState.BLOCK_COMMENT; + index++; + } else if (current == '"' + && index + 2 < end + && content.charAt(index + 1) == '"' + && content.charAt(index + 2) == '"') { + state = LexicalState.TEXT_BLOCK; + index += 2; + } else if (current == '"') { + state = LexicalState.STRING; + } else if (current == '\'') { + state = LexicalState.CHARACTER; + } + } + case LINE_COMMENT -> { + if (current == '\r' || current == '\n') { + state = LexicalState.NORMAL; + } + } + case BLOCK_COMMENT -> { + if (current == '*' && next == '/') { + state = LexicalState.NORMAL; + index++; + } + } + case STRING -> { + if (current == '\\') { + index++; + } else if (current == '"' || current == '\r' || current == '\n') { + state = LexicalState.NORMAL; + } + } + case CHARACTER -> { + if (current == '\\') { + index++; + } else if (current == '\'' || current == '\r' || current == '\n') { + state = LexicalState.NORMAL; + } + } + case TEXT_BLOCK -> { + if (current == '"' + && index + 2 < end + && content.charAt(index + 1) == '"' + && content.charAt(index + 2) == '"' + && !isEscaped(content, index)) { + state = LexicalState.NORMAL; + index += 2; + } + } + } + } + return state; + } + + private static boolean isEscaped(String content, int index) { + int backslashes = 0; + for (int cursor = index - 1; cursor >= 0 && content.charAt(cursor) == '\\'; cursor--) { + backslashes++; + } + return backslashes % 2 != 0; + } + + private enum LexicalState { + NORMAL, + LINE_COMMENT, + BLOCK_COMMENT, + STRING, + CHARACTER, + TEXT_BLOCK + } + + private static List knownInvalidImports(ASTOrdinaryCompilationUnit ast) { + return ast.getImportDeclarationList().stream() + .filter(JavaSourcePostProcessor::isKnownInvalidImport) + .toList(); + } + + private static boolean isKnownInvalidImport(ASTImportDeclaration importDeclaration) { + if (importDeclaration.isStatic()) { + return false; + } + String imported = importDeclaration.getMCQualifiedName().getQName(); + return Constants.ANNOT_PACKAGE.equals(imported) || !imported.contains("."); + } + + private static String primaryTypeFileName(String content) { + return parseOrdinaryCompilationUnit(content) + .flatMap(JavaSourcePostProcessor::primaryTypeName) + .map(name -> name + ".java") + .orElse("Generated.java"); + } + + private static Optional primaryTypeName(ASTOrdinaryCompilationUnit ast) { + return ast.getTypeDeclarationList().stream().findFirst().map(ASTTypeDeclaration::getName); + } + + private static String applyImportEdits( + String content, + List importsToRemove, + ASTOrdinaryCompilationUnit ast) { + if (importsToRemove.isEmpty()) { + return content; + } + + SourceDocument document = new SourceDocument(content); + List edits = new ArrayList<>(); + for (ASTImportDeclaration importToRemove : importsToRemove) { + int line = importToRemove.get_SourcePositionStart().getLine(); + if (line > 0) { + edits.add(new SourceEdit(document.lineStart(line), document.lineEndIncludingEnding(line), "")); + } + } + + return document.apply(edits); + } + + private record SourceState(String content) {} + + private record SourceEdit(int start, int end, String replacement) {} + + private static final class SourceDocument { + private final String content; + private final List lineStarts; + private final String lineSeparator; + + private SourceDocument(String content) { + this.content = content; + this.lineStarts = lineStarts(content); + this.lineSeparator = detectLineSeparator(content); + } + + private int lineStart(int line) { + if (line <= 1) { + return 0; + } + if (line > lineStarts.size()) { + return content.length(); + } + return lineStarts.get(line - 1); + } + + private int lineEndIncludingEnding(int line) { + if (line < lineStarts.size()) { + return lineStarts.get(line); + } + return content.length(); + } + + private String lineSeparator() { + return lineSeparator; + } + + private String apply(List edits) { + StringBuilder result = new StringBuilder(content); + edits.stream() + .sorted( + Comparator.comparingInt(SourceEdit::start) + .thenComparingInt(SourceEdit::end) + .reversed()) + .forEach(edit -> result.replace(edit.start(), edit.end(), edit.replacement())); + return result.toString(); + } + + private static List lineStarts(String content) { + List starts = new ArrayList<>(); + starts.add(0); + for (int i = 0; i < content.length(); i++) { + if (content.charAt(i) == '\n') { + starts.add(i + 1); + } + } + return starts; + } + + private static String detectLineSeparator(String content) { + int newline = content.indexOf('\n'); + if (newline > 0 && content.charAt(newline - 1) == '\r') { + return "\r\n"; + } + return "\n"; + } + } + +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/AnnotationRemover.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/AnnotationRemover.java index 440d6d4b..f4a914f0 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/AnnotationRemover.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/AnnotationRemover.java @@ -11,7 +11,6 @@ import de.monticore.statements.mccommonstatements._ast.ASTJavaModifier; import de.monticore.statements.mccommonstatements._visitor.MCCommonStatementsVisitor2; import de.monticore.statements.mcstatementsbasis._ast.ASTMCModifier; -import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; import de.monticore.statements.mcvardeclarationstatements._visitor.MCVarDeclarationStatementsVisitor2; import java.util.List; import java.util.Optional; diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/JavaAstElemCollector.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/JavaAstElemCollector.java index e5883a06..9f1d4fcc 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/JavaAstElemCollector.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/JavaAstElemCollector.java @@ -4,6 +4,7 @@ import de.monticore.java.javadsl._ast.*; import de.monticore.java.javadsl._visitor.JavaDSLTraverser; import de.monticore.java.javadsl._visitor.JavaDSLVisitor2; +import de.monticore.javalight._ast.ASTFormalParameterListing; import de.monticore.javalight._ast.ASTMethodDeclaration; import de.monticore.javalight._visitor.JavaLightVisitor2; import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; @@ -11,38 +12,64 @@ import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.util.*; -/*** - * this visitor collect Type, field,methods, local-variable and formal parameters - * from a ASTOrdinaryCompilationUnit +/** + * Collects top-level types and their fields, methods, supertypes, parameters, and local variables + * from an {@link ASTOrdinaryCompilationUnit}. + * + *

For example, in {@code void visit(Person input) { for (Person person : people) {} }}, {@code + * input} is collected as a method parameter and enhanced-for variable {@code person} as a local + * variable, although JavaDSL represents both with {@code ASTFormalParameter} nodes. */ - public class JavaAstElemCollector implements JavaDSLVisitor2 { private final List typeDeclarations = new ArrayList<>(); private final Map typeElements = new LinkedHashMap<>(); + private int typeNestingDepth; @Override public void visit(ASTClassDeclaration node) { - TypeElementCollector collector = visitType(node); - - collector.supertypesDeclarations.addAll(node.getImplementedInterfaceList()); - if (node.isPresentSuperClass()) { - collector.supertypesDeclarations.add(node.getSuperClass()); + if (typeNestingDepth == 0) { + TypeElementCollector collector = visitType(node); + collector.supertypesDeclarations.addAll(node.getImplementedInterfaceList()); + if (node.isPresentSuperClass()) { + collector.supertypesDeclarations.add(node.getSuperClass()); + } + typeElements.put(node, collector); } + typeNestingDepth++; + } - typeElements.put(node, collector); + @Override + public void endVisit(ASTClassDeclaration node) { + typeNestingDepth--; } @Override public void visit(ASTInterfaceDeclaration node) { - TypeElementCollector collector = visitType(node); - collector.supertypesDeclarations.addAll(node.getExtendedInterfaceList()); - typeElements.put(node, collector); + if (typeNestingDepth == 0) { + TypeElementCollector collector = visitType(node); + collector.supertypesDeclarations.addAll(node.getExtendedInterfaceList()); + typeElements.put(node, collector); + } + typeNestingDepth++; + } + + @Override + public void endVisit(ASTInterfaceDeclaration node) { + typeNestingDepth--; } @Override public void visit(ASTEnumDeclaration node) { - TypeElementCollector collector = visitType(node); - typeElements.put(node, collector); + if (typeNestingDepth == 0) { + TypeElementCollector collector = visitType(node); + typeElements.put(node, collector); + } + typeNestingDepth++; + } + + @Override + public void endVisit(ASTEnumDeclaration node) { + typeNestingDepth--; } private TypeElementCollector visitType(ASTTypeDeclaration node) { @@ -111,14 +138,58 @@ class TypeElementCollector implements JavaDSLVisitor2, JavaLightVisitor2 { Map> localVarsMap = new LinkedHashMap<>(); Map> formalParamsMap = new LinkedHashMap<>(); + private int typeNestingDepth; + + @Override + public void visit(ASTClassDeclaration node) { + typeNestingDepth++; + } + + @Override + public void endVisit(ASTClassDeclaration node) { + typeNestingDepth--; + } + + @Override + public void visit(ASTInterfaceDeclaration node) { + typeNestingDepth++; + } + + @Override + public void endVisit(ASTInterfaceDeclaration node) { + typeNestingDepth--; + } + + @Override + public void visit(ASTEnumDeclaration node) { + typeNestingDepth++; + } + + @Override + public void endVisit(ASTEnumDeclaration node) { + typeNestingDepth--; + } @Override public void visit(ASTMethodDeclaration node) { + if (typeNestingDepth != 1) { + return; + } methodDeclarations.add(node); List localVars = new ArrayList<>(); List formalParams = new ArrayList<>(); + // Collect method signature parameters directly from the method declaration. + // This avoids collecting for-each loop variables (which are also ASTFormalParameter + // in the grammar) as formal parameters — they should be treated as local variables. + Set signatureParams = new HashSet<>(); + if (node.getFormalParameters().isPresentFormalParameterListing()) { + ASTFormalParameterListing paramListing = node.getFormalParameters().getFormalParameterListing(); + formalParams.addAll(paramListing.getFormalParameterList()); + signatureParams.addAll(paramListing.getFormalParameterList()); + } + JavaDSLTraverser traverser = JavaDSLMill.traverser(); JavaDSLVisitor2 localVarCollector = @@ -129,23 +200,49 @@ public void visit(ASTLocalVariableDeclaration node) { } }; - MCCommonStatementsVisitor2 formalParamVisitor = + // For-each loop variables are ASTFormalParameter nodes in the method body. + // Collect them as local variables instead of formal parameters, + // since they have no CD-level parameter mapping. + // Filter out method signature parameters to avoid double-counting. + MCCommonStatementsVisitor2 forEachVarCollector = new MCCommonStatementsVisitor2() { @Override public void visit(ASTFormalParameter node) { - formalParams.add(node); + if (!signatureParams.contains(node)) { + localVars.add(wrapAsLocalVariable(node)); + } } }; traverser.add4JavaDSL(localVarCollector); - traverser.add4MCCommonStatements(formalParamVisitor); + traverser.add4MCCommonStatements(forEachVarCollector); node.accept(traverser); localVarsMap.put(node, localVars); formalParamsMap.put(node, formalParams); } + /** + * Wraps an ASTFormalParameter like from a for-each loop as an ASTLocalVariableDeclaration + * so it can be handled by the local variable matching path instead of the formal parameter path. + */ + private ASTLocalVariableDeclaration wrapAsLocalVariable(ASTFormalParameter param) { + ASTLocalVariableDeclaration localVar = JavaDSLMill.localVariableDeclarationBuilder() + .setMCType(param.getMCType()) + .build(); + localVar.set_SourcePositionStart(param.get_SourcePositionStart()); + localVar.set_SourcePositionEnd(param.get_SourcePositionEnd()); + var variableDeclarator = + JavaDSLMill.variableDeclaratorBuilder().setDeclarator(param.getDeclarator()).build(); + variableDeclarator.set_SourcePositionStart(param.get_SourcePositionStart()); + variableDeclarator.set_SourcePositionEnd(param.get_SourcePositionEnd()); + localVar.getVariableDeclaratorList().add(variableDeclarator); + return localVar; + } + @Override public void visit(ASTFieldDeclaration node) { - fieldDeclarations.add(node); + if (typeNestingDepth == 1) { + fieldDeclarations.add(node); + } } } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/CodeValidator.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/CodeValidator.java index dc35fec5..e444989a 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/CodeValidator.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/CodeValidator.java @@ -29,7 +29,6 @@ import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; import de.monticore.codeAdaption.validator.cocos.OneVarInDeclaration; import de.monticore.codeAdaption.validator.cocos.ValidAnnotation; -import de.monticore.codeAdaption.validator.cocos.ValidTemplate; import de.monticore.java.javadsl.JavaDSLMill; import de.monticore.java.javadsl._ast.ASTFieldDeclaration; import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; @@ -39,22 +38,44 @@ import de.monticore.java.javadsl._visitor.JavaDSLTraverser; import de.monticore.javalight._ast.ASTMethodDeclaration; import de.monticore.javalight._cocos.JavaLightASTAnnotationCoCo; -import de.monticore.javalight._cocos.JavaLightASTMethodDeclarationCoCo; import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; -import de.monticore.statements.mccommonstatements._cocos.MCCommonStatementsASTFormalParameterCoCo; import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.se_rwth.commons.logging.Log; import java.nio.file.Path; import java.util.*; -/*** - * this class check if a reference Code is valid for the given reference code. +/** + * Validates whether handwritten reference Java can be processed safely against a reference class + * diagram and exposes the matchings used by the update phase. + * + *

Validation performs three checks: + * + *

    + *
  • The adapter-specific {@link ValidAnnotation} CoCo requires each non-ignored {@code @Adapt} + * annotation to define a template, requires its placeholder count to match its reference + * count, and requires every named reference to resolve in the reference CD. + *
  • The {@link OneVarInDeclaration} CoCo rejects field and local-variable declarations such as + * {@code String first, second;} because the updater addresses one declarator at a time. + *
  • The configured matcher chains are queried for every relevant Java type, field, method, + * parameter, and local variable. Depending on the {@link AdapterParam} settings, an + * unmatched element is either accepted by an ignore matcher or reported by an error matcher. + *
+ * + *

This class does not compile the Java source, run the complete JavaDSL or CD4Code CoCo suites, + * or check CD conformance. Those responsibilities belong to the Java compiler and the dedicated + * conformance/concretization services. */ - public class CodeValidator { private final CompTypeMatcher typeMatcher; private final CompTMemberMatcher tMemberMatcher; private final CompVariableMatcher variableMatcher; + /** + * Creates the matcher chains in configured precedence order. + * + * @param cd reference class diagram used to resolve Java elements + * @param params enabled matching and unmatched-element policies + */ public CodeValidator(ASTCDCompilationUnit cd, Set params) { List typeMatchers = new ArrayList<>(); List tMemberMatchers = new ArrayList<>(); @@ -102,35 +123,97 @@ public CodeValidator(ASTCDCompilationUnit cd, Set params) { tMemberMatcher.setTypeMatcher(typeMatcher); } + /** + * Parses all reference Java files, runs the adapter CoCos, and verifies matcher coverage. + * + * @param refCD reference CD used by annotation validation + * @param refCode directory containing handwritten reference Java + * @return {@code true} if this validation run produced no new error findings + */ public boolean isValid(ASTCDCompilationUnit refCD, Path refCode) { - Set asts = readJavaCode(refCode); + boolean failQuickEnabled = Log.isFailQuickEnabled(); + int findingsBefore = Log.getFindings().size(); + long errorsBefore = Log.getErrorCount(); + boolean valid; + List diagnostics = List.of(); + try { + Log.enableFailQuick(false); + Set asts = readJavaCode(refCode); + + // Check the adapter-specific CoCos before matcher queries can add further findings. + asts.forEach(ast -> runAdapterCoCos(ast, refCD)); - // check cocos phase 1 - asts.forEach(ast -> runCoCosPhase1(ast, refCD)); + // Collect the complete source scope before any matcher query. ErrorTMemberMatcher uses this + // scope to distinguish a valid source-local supertype from an unmatched external type. + Set allTypes = new LinkedHashSet<>(); + List collectors = new ArrayList<>(); + for (ASTOrdinaryCompilationUnit ast : asts) { + JavaAstElemCollector collector = new JavaAstElemCollector(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(collector); + ast.accept(traverser); - // cocos phase 2 - asts.forEach(ast -> runCoCosPhase2(ast, refCD)); + collectors.add(collector); + allTypes.addAll(collector.getAllTypeDeclarations()); + } + typeMatcher.setAllTypeDeclarations(allTypes); - // check that all elements matched - Set allType = new LinkedHashSet<>(); - for (ASTOrdinaryCompilationUnit ast : asts) { + // Check that every relevant element has a match only after the complete scope is available. + for (JavaAstElemCollector collector : collectors) { + checkAllMatching(collector); + } + valid = Log.getErrorCount() == errorsBefore; + if (!valid) { + diagnostics = + Log.getFindings().subList(findingsBefore, Log.getFindings().size()).stream() + .map(finding -> finding.getMsg()) + .distinct() + .toList(); + } + } finally { + if (Log.getErrorCount() > errorsBefore && Log.getFindings().size() > findingsBefore) { + Log.getFindings().subList(findingsBefore, Log.getFindings().size()).clear(); + } + Log.enableFailQuick(failQuickEnabled); + } + diagnostics.forEach(message -> Log.warn("Reference-code validation: " + message)); + return valid; + } + + /** + * Initializes the type matcher with all declarations from the supplied compilation units. + * + *

The complete type set is needed by matchers that decide whether a type name is unique in the + * current source batch. + * + * @param javaFiles Java compilation units whose type declarations form the matching scope + */ + public void initializeTypeMatcher(Set javaFiles) { + Set allTypes = new LinkedHashSet<>(); + + for (ASTOrdinaryCompilationUnit ast : javaFiles) { JavaAstElemCollector collector = new JavaAstElemCollector(); JavaDSLTraverser traverser = JavaDSLMill.traverser(); traverser.add4JavaDSL(collector); ast.accept(traverser); - allType.addAll(collector.getAllTypeDeclarations()); - checkAllMatching(collector); + allTypes.addAll(collector.getAllTypeDeclarations()); } - typeMatcher.setAllTypeDeclarations(allType); - return true; + typeMatcher.setAllTypeDeclarations(allTypes); } + /** + * Queries every configured matcher so missing required matches are emitted before adaptation. + * Member and variable matchers are only queried when their enclosing type or method matched. + */ protected void checkAllMatching(JavaAstElemCollector collector) { for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { if (getMatchedType(type).isPresent()) { + collector + .getAllFSuperTypeDeclarations(type) + .forEach(supertype -> getMatchedSupertype(type, supertype)); collector.getAllFieldDeclarations(type).forEach(f -> getMatchedField(type, f)); for (ASTMethodDeclaration method : collector.getAllMethodDeclarations(type)) { @@ -147,35 +230,45 @@ protected void checkAllMatching(JavaAstElemCollector collector) { } } + /** Returns the configured matching for a Java method, if a matcher accepted it. */ public Optional getMatchedMethod( ASTTypeDeclaration type, ASTMethodDeclaration element) { return tMemberMatcher.getMatchedMethod(type, element); } + /** Returns the configured matching for a Java field, if a matcher accepted it. */ public Optional getMatchedField( ASTTypeDeclaration type, ASTFieldDeclaration element) { return tMemberMatcher.getMatchedField(type, element); } + /** Returns the configured matching for a declared Java supertype, if one exists. */ public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType supertype) { return tMemberMatcher.getMatchedSupertype(type, supertype); } + /** Returns the configured matching for a Java type declaration, if a matcher accepted it. */ public Optional getMatchedType(ASTTypeDeclaration element) { return typeMatcher.getMatchedType(element); } + /** Returns the configured matching for a local variable inside the supplied method. */ public Optional getMatchedLocalVariable( ASTTypeDeclaration type, ASTMethodDeclaration method, ASTLocalVariableDeclaration element) { return variableMatcher.getMatchedLocalVariable(type, method, element); } + /** Returns the configured matching for a formal parameter inside the supplied method. */ public Optional getMatchedParameter( ASTTypeDeclaration type, ASTMethodDeclaration method, ASTFormalParameter element) { return variableMatcher.getMatchedFormalParameter(type, method, element); } - protected void runCoCosPhase1(ASTOrdinaryCompilationUnit ast, ASTCDCompilationUnit refCD) { + /** + * Runs only the adapter-specific annotation and single-variable-declaration CoCos on one Java + * compilation unit. + */ + protected void runAdapterCoCos(ASTOrdinaryCompilationUnit ast, ASTCDCompilationUnit refCD) { JavaDSLCoCoChecker checker = new JavaDSLCoCoChecker(); checker.addCoCo((JavaDSLASTJavaAnnotationCoCo) new ValidAnnotation(refCD)); checker.addCoCo((JavaLightASTAnnotationCoCo) new ValidAnnotation(refCD)); @@ -183,13 +276,4 @@ protected void runCoCosPhase1(ASTOrdinaryCompilationUnit ast, ASTCDCompilationUn checker.addCoCo((JavaDSLASTFieldDeclarationCoCo) new OneVarInDeclaration()); checker.checkAll(ast); } - - protected void runCoCosPhase2(ASTOrdinaryCompilationUnit ast, ASTCDCompilationUnit refCD) { - JavaDSLCoCoChecker checker = new JavaDSLCoCoChecker(); - // implicitly also adds CoCo to JavaDSLASTLocalVariableDeclaration - checker.addCoCo((JavaDSLASTTypeDeclarationCoCo) new ValidTemplate(refCD)); - checker.addCoCo((JavaLightASTMethodDeclarationCoCo) new ValidTemplate(refCD)); - checker.addCoCo((MCCommonStatementsASTFormalParameterCoCo) new ValidTemplate(refCD)); - checker.checkAll(ast); - } } diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidAnnotation.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidAnnotation.java index e78822a9..a839fc2a 100644 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidAnnotation.java +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidAnnotation.java @@ -1,13 +1,12 @@ package de.monticore.codeAdaption.validator.cocos; import static de.monticore.codeAdaption.utils.AdapterUtils.getPosition; -import static de.monticore.codeAdaption.utils.Constants.*; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.codeAdaption.matcher.annotMatcher.AnnotElementCollector; +import de.monticore.codeAdaption.utils.AdaptAnnotationNames; import de.monticore.codeAdaption.utils.AdapterUtils; import de.monticore.codeAdaption.utils.Constants; -import de.monticore.codeAdaption.utils.JavaLoader; import de.monticore.java.javadsl.JavaDSLMill; import de.monticore.java.javadsl._ast.ASTJavaAnnotation; import de.monticore.java.javadsl._cocos.JavaDSLASTJavaAnnotationCoCo; @@ -41,14 +40,14 @@ public ValidAnnotation(ASTCDCompilationUnit cd) { @Override public void check(ASTJavaAnnotation node) { - if (JavaLoader.print(node.getAnnotationName()).endsWith(ANNOT_NAME)) { + if (AdaptAnnotationNames.matches(node.getAnnotationName().getQName())) { checkAnnotation(node); } } @Override public void check(ASTAnnotation node) { - if (JavaLoader.print(node.getAnnotationName()).endsWith(ANNOT_NAME)) { + if (AdaptAnnotationNames.matches(node.getAnnotationName().getQName())) { checkAnnotation(node); } } @@ -68,14 +67,10 @@ public void checkAnnotation(ASTMCModifier node) { Log.error(String.format(missingTemplate, pos)); } - // template argument == references - long arguments = - collector.getTemplate() == null - ? 0 - : collector.getTemplate().chars().filter(s -> (char) s == '$').count(); long references = collector.getReferences().size(); - if (arguments != collector.getReferences().size()) { - Log.error(String.format(templateArguments, pos, references, arguments)); + validateTemplateArity(collector.getTemplate(), references, pos); + if (collector.getGenTemplate() != null && !collector.getGenTemplate().isBlank()) { + validateTemplateArity(collector.getGenTemplate(), references, pos); } // reference must exist in the class diagram @@ -88,6 +83,15 @@ public void checkAnnotation(ASTMCModifier node) { } } + private void validateTemplateArity(String template, long references, String pos) { + long arguments = template == null ? 0 : extractPlaceHolders(template).size(); + // A constant template is valid and intentionally ignores its references. As soon as a + // placeholder is used, every reference must have a corresponding placeholder. + if (arguments > 0 && arguments != references) { + Log.error(String.format(templateArguments, pos, references, arguments)); + } + } + public static List extractPlaceHolders(String template) { List matches = new ArrayList<>(); Pattern pattern = Pattern.compile(Constants.PLACE_HOLDER_REGEX); diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidTemplate.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidTemplate.java deleted file mode 100644 index d8751254..00000000 --- a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidTemplate.java +++ /dev/null @@ -1,92 +0,0 @@ -package de.monticore.codeAdaption.validator.cocos; - -import static de.monticore.codeAdaption.matcher.MatcherHelper.*; - -import de.monticore.cdbasis._ast.ASTCDCompilationUnit; -import de.monticore.codeAdaption.matcher.CodeMatching; -import de.monticore.codeAdaption.matcher.MatcherHelper; -import de.monticore.codeAdaption.utils.AdapterUtils; -import de.monticore.java.javadsl._ast.*; -import de.monticore.java.javadsl._cocos.JavaDSLASTFieldDeclarationCoCo; -import de.monticore.java.javadsl._cocos.JavaDSLASTLocalVariableDeclarationCoCo; -import de.monticore.java.javadsl._cocos.JavaDSLASTTypeDeclarationCoCo; -import de.monticore.javalight._ast.ASTAnnotation; -import de.monticore.javalight._ast.ASTMethodDeclaration; -import de.monticore.javalight._cocos.JavaLightASTMethodDeclarationCoCo; -import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; -import de.monticore.statements.mccommonstatements._cocos.MCCommonStatementsASTFormalParameterCoCo; -import de.monticore.statements.mcstatementsbasis._ast.ASTMCModifier; -import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; -import de.se_rwth.commons.logging.Log; -import java.util.Optional; - -public class ValidTemplate - implements JavaDSLASTFieldDeclarationCoCo, - JavaDSLASTTypeDeclarationCoCo, - JavaLightASTMethodDeclarationCoCo, - MCCommonStatementsASTFormalParameterCoCo, - JavaDSLASTLocalVariableDeclarationCoCo { - protected ASTCDCompilationUnit cd; - - public ValidTemplate(ASTCDCompilationUnit cd) { - this.cd = cd; - } - - protected String message = - "0xRC003 %s invalid annotation template: filling template [%s] with the references " - + " produce [%s]. But expected [%s].\n" - + "allowed templates placeholder are {${},${cap_first} and ${uncap_first} }"; - - @Override - public void check(ASTMethodDeclaration node) { - Optional annotation = getInfoAnnotation(node.getMCModifierList()); - annotation.ifPresent(astJavaAnnotation -> checkTemplate(astJavaAnnotation, node.getName())); - } - - @Override - public void check(ASTFieldDeclaration node) { - String srcName = node.getVariableDeclarator(0).getDeclarator().getName(); - Optional annotation = getInfoJavaAnnot(node.getJavaModifierList()); - annotation.ifPresent(astJavaAnnotation -> checkTemplate(astJavaAnnotation, srcName)); - } - - @Override - public void check(ASTTypeDeclaration node) { - Optional annotation = Optional.empty(); - if (node instanceof ASTClassDeclaration) { - annotation = getInfoJavaAnnot(((ASTClassDeclaration) node).getJavaModifierList()); - } else if (node instanceof ASTInterfaceDeclaration) { - annotation = getInfoJavaAnnot(((ASTInterfaceDeclaration) node).getJavaModifierList()); - } else if (node instanceof ASTEnumDeclaration) { - annotation = getInfoJavaAnnot(((ASTEnumDeclaration) node).getJavaModifierList()); - } - - annotation.ifPresent(astJavaAnnotation -> checkTemplate(astJavaAnnotation, node.getName())); - } - - @Override - public void check(ASTFormalParameter node) { - Optional annotation = getInfoJavaAnnot(node.getJavaModifierList()); - annotation.ifPresent( - astJavaAnnotation -> checkTemplate(astJavaAnnotation, node.getDeclarator().getName())); - } - - @Override - public void check(ASTLocalVariableDeclaration node) { - String srcName = node.getVariableDeclarator(0).getDeclarator().getName(); - Optional annotation = getInfoAnnotation(node.getMCModifierList()); - annotation.ifPresent(astJavaAnnotation -> checkTemplate(astJavaAnnotation, srcName)); - } - - public void checkTemplate(ASTMCModifier annotation, String sourceNAme) { - String pos = AdapterUtils.getPosition(annotation.get_SourcePositionStart()); - CodeMatching matching = mkMatchingFromAnnotation(annotation, cd); - if (matching.getTemplate() != null) { - String computedName = - MatcherHelper.fillTemplate(matching.getTemplate(), matching.getReferences()); - if (!computedName.equals(sourceNAme)) { - Log.error(String.format(message, pos, matching.getTemplate(), computedName, sourceNAme)); - } - } - } -} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdaptedCodeMergerTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdaptedCodeMergerTest.java new file mode 100644 index 00000000..a6716b62 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdaptedCodeMergerTest.java @@ -0,0 +1,592 @@ +package de.monticore.codeAdaption; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashSet; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class AdaptedCodeMergerTest extends AdapterAbstractTest { + + @TempDir Path tempDir; + + private AdaptedCodeMerger merger; + + @BeforeEach + void setUp() { + initMills(); + merger = new AdaptedCodeMerger(); + } + + @Test + void preservesSameSimpleTypeNameInDifferentPackages() throws IOException { + ASTOrdinaryCompilationUnit first = + parse("a/User.java", "package a; public class User { int first; }"); + ASTOrdinaryCompilationUnit second = + parse("b/User.java", "package b; public class User { int second; }"); + + Set merged = + merger.mergeAdaptedCode(new LinkedHashSet<>(), linkedSet(second, first)); + + assertEquals(2, merged.size()); + assertEquals( + Set.of("a", "b"), + merged.stream() + .map(unit -> unit.getPackageDeclaration().getMCQualifiedName().getQName()) + .collect(java.util.stream.Collectors.toSet())); + } + + @Test + void mergesValidSameNameOverloads() throws IOException { + ASTOrdinaryCompilationUnit first = + parse("first/Service.java", "package p; public class Service { void run(String value) {} }"); + ASTOrdinaryCompilationUnit second = + parse("second/Service.java", "package p; public class Service { void run(int value) {} }"); + + ASTOrdinaryCompilationUnit merged = + merger.mergeAdaptedCode(linkedSet(first), linkedSet(second)).iterator().next(); + JavaAstElemCollector collector = collect(merged); + + assertEquals( + 2, + collector + .getAllMethodDeclarations(merged.getTypeDeclarationList().get(0)) + .size()); + } + + @Test + void mergesMethodsProducedBySeparateIncarnationPasses() throws IOException { + ASTOrdinaryCompilationUnit math = + parse( + "math/Teacher.java", + "package Concrete; class Teacher { MathDept firstMathDept(MathDept fallback) { return fallback; } }"); + ASTOrdinaryCompilationUnit science = + parse( + "science/Teacher.java", + "package Concrete; class Teacher { ScienceDept firstScienceDept(ScienceDept fallback) { return fallback; } }"); + + Set merged = + merger.mergeAdaptedCode( + merger.mergeAdaptedCode(new LinkedHashSet<>(), linkedSet(math)), + linkedSet(science)); + ASTOrdinaryCompilationUnit teacher = merged.iterator().next(); + JavaAstElemCollector collector = collect(teacher); + + assertEquals( + Set.of("firstMathDept", "firstScienceDept"), + collector.getAllMethodDeclarations(teacher.getTypeDeclarationList().get(0)).stream() + .map(de.monticore.javalight._ast.ASTMethodDeclaration::getName) + .collect(java.util.stream.Collectors.toSet())); + } + + @Test + void splitKeepsNestedTypesInsideTheirTopLevelOwner() throws IOException { + ASTOrdinaryCompilationUnit source = + parse( + "Combined.java", + "package p; class Outer { static class Inner { void nested() {} } void outer() {} } " + + "class Second {}"); + + Set split = merger.splitCompilationUnitsByType(linkedSet(source)); + + assertEquals(2, split.size()); + ASTOrdinaryCompilationUnit outer = + split.stream() + .filter(unit -> unit.getTypeDeclarationList().get(0).getName().equals("Outer")) + .findFirst() + .orElseThrow(); + assertEquals(1, outer.getTypeDeclarationList().size()); + assertTrue(JavaLoader.print(outer).contains("class Inner")); + + JavaAstElemCollector collector = collect(outer); + assertEquals(1, collector.getAllTypeDeclarations().size()); + assertEquals( + 1, + collector + .getAllMethodDeclarations(outer.getTypeDeclarationList().get(0)) + .size()); + } + + @Test + void mergesAdaptedTypeIntoUniqueConcreteTypeAcrossPackages() throws IOException { + ASTOrdinaryCompilationUnit adapted = + parse("adapter/Port.java", "package adapter; interface Port { void send(); }"); + ASTOrdinaryCompilationUnit concrete = + parse("concrete/Port.java", "package concrete; interface Port {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { interface Port; }"); + + ASTOrdinaryCompilationUnit merged = + merger + .mergeAdaptedCodeIntoConcreteBase( + linkedSet(concrete), + linkedSet(adapted), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))) + .iterator() + .next(); + + assertEquals( + "concrete", merged.getPackageDeclaration().getMCQualifiedName().getQName()); + assertTrue(JavaLoader.print(merged).contains("void send()")); + } + + @Test + void preservesCompletedAbstractnessWhenMergingIntoConcreteCode() throws IOException { + ASTOrdinaryCompilationUnit adapted = + parse( + "adapter/BankAccount.java", + "package adapter; abstract class BankAccount implements Auditable {}"); + ASTOrdinaryCompilationUnit concrete = + parse("concrete/BankAccount.java", "package concrete; class BankAccount {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { abstract class BankAccount; }"); + + ASTOrdinaryCompilationUnit merged = + merger + .mergeAdaptedCodeIntoConcreteBase( + linkedSet(concrete), + linkedSet(adapted), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))) + .stream() + .filter(unit -> unit.getTypeDeclarationList().get(0).getName().equals("BankAccount")) + .findFirst() + .orElseThrow(); + + String rendered = JavaLoader.print(merged); + assertTrue(rendered.contains("abstract class BankAccount"), rendered); + assertTrue(rendered.contains("implements Auditable"), rendered); + } + + @Test + void removesStaleAbstractnessWhenCompletedTypeIsConcrete() throws IOException { + ASTOrdinaryCompilationUnit adapted = + parse("adapter/BankAccount.java", "package adapter; class BankAccount {}"); + ASTOrdinaryCompilationUnit concrete = + parse( + "concrete/BankAccount.java", + "package concrete; public abstract class BankAccount {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class BankAccount; }"); + + ASTOrdinaryCompilationUnit merged = + merger + .mergeAdaptedCodeIntoConcreteBase( + linkedSet(concrete), + linkedSet(adapted), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))) + .iterator() + .next(); + + String rendered = JavaLoader.print(merged); + assertTrue(rendered.contains("public class BankAccount"), rendered); + assertFalse(rendered.contains("abstract class BankAccount"), rendered); + } + + @Test + void importsRelocatedTypesIntoDependentAdaptedUnits() throws IOException { + ASTOrdinaryCompilationUnit adaptedAccount = + parse("adapter/Account.java", "package adapter; class Account {}"); + ASTOrdinaryCompilationUnit adaptedTransaction = + parse( + "adapter/Transaction.java", + "package adapter; class Transaction { Account source; }"); + ASTOrdinaryCompilationUnit concreteAccount = + parse("concrete/Account.java", "package concrete; class Account {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Account; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(concreteAccount), + linkedSet(adaptedAccount, adaptedTransaction), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + ASTOrdinaryCompilationUnit transaction = + merged.stream() + .filter(unit -> unit.getTypeDeclarationList().get(0).getName().equals("Transaction")) + .findFirst() + .orElseThrow(); + assertEquals( + Set.of("concrete.Account"), + transaction.getImportDeclarationList().stream() + .map(importDeclaration -> importDeclaration.getMCQualifiedName().getQName()) + .collect(java.util.stream.Collectors.toSet())); + } + + @Test + void importsRelocatedSuperclassIntoDependentAdaptedType() throws IOException { + ASTOrdinaryCompilationUnit adaptedBase = + parse("adapter/Base.java", "package adapter; class Base {}"); + ASTOrdinaryCompilationUnit adaptedChild = + parse("adapter/Child.java", "package adapter; class Child extends Base {}"); + ASTOrdinaryCompilationUnit concreteBase = + parse("domain/Base.java", "package domain; class Base {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Base; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(concreteBase), + linkedSet(adaptedBase, adaptedChild), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + ASTOrdinaryCompilationUnit child = + merged.stream() + .filter(unit -> unit.getTypeDeclarationList().get(0).getName().equals("Child")) + .findFirst() + .orElseThrow(); + assertTrue(JavaLoader.print(child).contains("import domain.Base;")); + } + + @Test + void memberImportRepairPreservesUnrelatedExplicitImportBinding() throws IOException { + ASTOrdinaryCompilationUnit consumer = + parse( + "adapter/Consumer.java", + "package adapter; import java.util.Date; class Consumer { Date createdAt; }"); + ASTOrdinaryCompilationUnit domainDate = + parse("domain/Date.java", "package domain; class Date {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Date; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(domainDate), + linkedSet(consumer), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + String rendered = JavaLoader.print(unitNamed(merged, "Consumer")); + assertTrue(rendered.contains("import java.util.Date;"), rendered); + assertFalse(rendered.contains("import domain.Date;"), rendered); + } + + @Test + void memberImportRepairAcceptsExactExplicitImportBinding() throws IOException { + ASTOrdinaryCompilationUnit consumer = + parse( + "adapter/Consumer.java", + "package adapter; import domain.Date; class Consumer { Date createdAt; }"); + ASTOrdinaryCompilationUnit domainDate = + parse("domain/Date.java", "package domain; class Date {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Date; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(domainDate), + linkedSet(consumer), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + String rendered = JavaLoader.print(unitNamed(merged, "Consumer")); + assertTrue(rendered.contains("import domain.Date;"), rendered); + } + + @Test + void memberImportRepairPreservesImplicitJavaLangBinding() throws IOException { + ASTOrdinaryCompilationUnit consumer = + parse("adapter/Consumer.java", "package adapter; class Consumer { Runnable action; }"); + ASTOrdinaryCompilationUnit domainRunnable = + parse("domain/Runnable.java", "package domain; class Runnable {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Runnable; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(domainRunnable), + linkedSet(consumer), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + String rendered = JavaLoader.print(unitNamed(merged, "Consumer")); + assertTrue(rendered.contains("Runnable action"), rendered); + assertFalse(rendered.contains("import domain.Runnable;"), rendered); + } + + @Test + void memberImportRepairAddsExplicitImportUnderUnrelatedWildcard() throws IOException { + ASTOrdinaryCompilationUnit consumer = + parse( + "adapter/Consumer.java", + "package adapter; import java.io.*; class Consumer { Date createdAt; }"); + ASTOrdinaryCompilationUnit domainDate = + parse("domain/Date.java", "package domain; class Date {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Date; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(domainDate), + linkedSet(consumer), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + String rendered = JavaLoader.print(unitNamed(merged, "Consumer")); + assertTrue(rendered.contains("import java.io.*;"), rendered); + assertTrue(rendered.contains("import domain.Date;"), rendered); + } + + @Test + void memberImportRepairPreservesMatchingPlatformWildcardBinding() throws IOException { + ASTOrdinaryCompilationUnit consumer = + parse( + "adapter/Consumer.java", + "package adapter; import java.util.*; class Consumer { Date createdAt; }"); + ASTOrdinaryCompilationUnit domainDate = + parse("domain/Date.java", "package domain; class Date {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Date; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(domainDate), + linkedSet(consumer), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + String rendered = JavaLoader.print(unitNamed(merged, "Consumer")); + assertTrue(rendered.contains("import java.util.*;"), rendered); + assertFalse(rendered.contains("import domain.Date;"), rendered); + } + + @Test + void memberImportRepairAcceptsMatchingWildcardBinding() throws IOException { + ASTOrdinaryCompilationUnit consumer = + parse( + "adapter/Consumer.java", + "package adapter; import domain.*; class Consumer { Date createdAt; }"); + ASTOrdinaryCompilationUnit domainDate = + parse("domain/Date.java", "package domain; class Date {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Date; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(domainDate), + linkedSet(consumer), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + String rendered = JavaLoader.print(unitNamed(merged, "Consumer")); + assertTrue(rendered.contains("import domain.*;"), rendered); + assertFalse(rendered.contains("import domain.Date;"), rendered); + } + + @Test + void memberImportRepairUsesUniqueMatchingWildcardDespiteUnrelatedOutputCandidate() + throws IOException { + ASTOrdinaryCompilationUnit consumer = + parse( + "adapter/Consumer.java", + "package adapter; import domain.*; class Consumer { Date createdAt; }"); + ASTOrdinaryCompilationUnit domainDate = + parse("domain/Date.java", "package domain; class Date {}"); + ASTOrdinaryCompilationUnit unrelatedDate = + parse("other/Date.java", "package other; class Date {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Date; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(domainDate, unrelatedDate), + linkedSet(consumer), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + String rendered = JavaLoader.print(unitNamed(merged, "Consumer")); + assertTrue(rendered.contains("import domain.*;"), rendered); + assertFalse(rendered.contains("import domain.Date;"), rendered); + } + + @Test + void memberImportRepairDoesNotRebindConcreteOnlyReference() throws IOException { + ASTOrdinaryCompilationUnit concreteConsumer = + parse( + "concrete/Consumer.java", + "package adapter; class Consumer { External handwritten; }"); + ASTOrdinaryCompilationUnit adaptedConsumer = + parse( + "adapter/Consumer.java", + "package adapter; class Consumer { void generated() {} }"); + ASTOrdinaryCompilationUnit domainExternal = + parse("domain/External.java", "package domain; class External {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Consumer; class External; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(concreteConsumer, domainExternal), + linkedSet(adaptedConsumer), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + String rendered = JavaLoader.print(unitNamed(merged, "Consumer")); + assertTrue(rendered.contains("External handwritten"), rendered); + assertFalse(rendered.contains("import domain.External;"), rendered); + } + + @Test + void memberImportRepairDoesNotImportForQualifiedReference() throws IOException { + ASTOrdinaryCompilationUnit consumer = + parse( + "adapter/Consumer.java", + "package adapter; class Consumer { foreign.Date createdAt; }"); + ASTOrdinaryCompilationUnit domainDate = + parse("domain/Date.java", "package domain; class Date {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Date; }"); + + Set merged = + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(domainDate), + linkedSet(consumer), + CDModelIndex.of(JavaLoader.parseCD(cd.toString()))); + + String rendered = JavaLoader.print(unitNamed(merged, "Consumer")); + assertTrue(rendered.contains("foreign.Date createdAt"), rendered); + assertFalse(rendered.contains("import domain.Date;"), rendered); + } + + @Test + void rejectsConflictingImportForRelocatedType() throws IOException { + ASTOrdinaryCompilationUnit adaptedAccount = + parse("adapter/Account.java", "package adapter; class Account {}"); + ASTOrdinaryCompilationUnit adaptedTransaction = + parse( + "adapter/Transaction.java", + "package adapter; import other.Account; class Transaction { Account source; }"); + ASTOrdinaryCompilationUnit concreteAccount = + parse("concrete/Account.java", "package concrete; class Account {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Account; }"); + + assertThrows( + CodeAdaptationException.class, + () -> + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(concreteAccount), + linkedSet(adaptedAccount, adaptedTransaction), + CDModelIndex.of(JavaLoader.parseCD(cd.toString())))); + } + + @Test + void rejectsConflictingImportsFromSeparateMappingPasses() throws IOException { + ASTOrdinaryCompilationUnit first = + parse("first/Service.java", "package p; import a.User; class Service {}"); + ASTOrdinaryCompilationUnit second = + parse("second/Service.java", "package p; import b.User; class Service {}"); + + IllegalStateException exception = + assertThrows( + IllegalStateException.class, + () -> merger.mergeAdaptedCode(linkedSet(first), linkedSet(second))); + + assertTrue(exception.getMessage().contains("both use the type name 'User'")); + } + + @Test + void keepsStaticAndWildcardImportsInSeparateNamespaces() throws IOException { + ASTOrdinaryCompilationUnit first = + parse( + "first/Service.java", + "package p; import a.User; import a.*; class Service {}"); + ASTOrdinaryCompilationUnit second = + parse( + "second/Service.java", + "package p; import static b.User; import b.*; class Service {}"); + + ASTOrdinaryCompilationUnit merged = + merger.mergeAdaptedCode(linkedSet(first), linkedSet(second)).iterator().next(); + + assertEquals(4, merged.getImportDeclarationList().size()); + } + + @Test + void rejectsConflictingImportsWhenMergingIntoConcreteCode() throws IOException { + ASTOrdinaryCompilationUnit concrete = + parse("concrete/Service.java", "package p; import a.User; class Service {}"); + ASTOrdinaryCompilationUnit adapted = + parse("adapted/Service.java", "package p; import b.User; class Service { void run() {} }"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Service; }"); + + assertThrows( + IllegalStateException.class, + () -> + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(concrete), + linkedSet(adapted), + CDModelIndex.of(JavaLoader.parseCD(cd.toString())))); + } + + @Test + void mergesEnumConstantsFromAdaptedAndConcreteSources() throws IOException { + ASTOrdinaryCompilationUnit concrete = + parse("concrete/Colour.java", "package p; enum Colour { RED, BLUE }"); + ASTOrdinaryCompilationUnit adapted = + parse("adapted/Colour.java", "package p; enum Colour { RED, GREEN }"); + + ASTOrdinaryCompilationUnit merged = + merger.mergeAdaptedCode(linkedSet(concrete), linkedSet(adapted)).iterator().next(); + + assertTrue(JavaLoader.print(merged).replaceAll("\\s+", "").contains("RED,GREEN,BLUE")); + } + + @Test + void rejectsAmbiguousConcretePackageForAdaptedType() throws IOException { + ASTOrdinaryCompilationUnit adapted = + parse("adapter/Account.java", "package adapter; class Account {}"); + ASTOrdinaryCompilationUnit first = + parse("first/Account.java", "package first; class Account {}"); + ASTOrdinaryCompilationUnit second = + parse("second/Account.java", "package second; class Account {}"); + Path cd = tempDir.resolve("Concrete.cd"); + Files.writeString(cd, "classdiagram Concrete { class Account; }"); + + CodeAdaptationException exception = + assertThrows( + CodeAdaptationException.class, + () -> + merger.mergeAdaptedCodeIntoConcreteBase( + linkedSet(first, second), + linkedSet(adapted), + CDModelIndex.of(JavaLoader.parseCD(cd.toString())))); + + assertTrue(exception.getMessage().contains("multiple packages")); + } + + private ASTOrdinaryCompilationUnit parse(String relativePath, String source) throws IOException { + Path file = tempDir.resolve(relativePath); + Files.createDirectories(file.getParent()); + Files.writeString(file, source); + return JavaLoader.loadJava(file.toFile()); + } + + private ASTOrdinaryCompilationUnit unitNamed( + Set units, String typeName) { + return units.stream() + .filter(unit -> unit.getTypeDeclarationList().get(0).getName().equals(typeName)) + .findFirst() + .orElseThrow(); + } + + @SafeVarargs + private static LinkedHashSet linkedSet(T... values) { + return new LinkedHashSet<>(java.util.List.of(values)); + } + + private static JavaAstElemCollector collect(ASTOrdinaryCompilationUnit unit) { + JavaAstElemCollector collector = new JavaAstElemCollector(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(collector); + unit.accept(traverser); + return collector; + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdapterAbstractTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdapterAbstractTest.java index ce994ab8..27c78736 100644 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdapterAbstractTest.java +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdapterAbstractTest.java @@ -1,8 +1,30 @@ package de.monticore.codeAdaption; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import de.monticore.cd._symboltable.BuiltInTypes; import de.monticore.cd4code.CD4CodeMill; +import de.monticore.cdconcretization.UnderspecifiedPlaceholderType; import de.monticore.java.javadsl.JavaDSLMill; import de.se_rwth.commons.logging.Log; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.tools.JavaCompiler; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; public abstract class AdapterAbstractTest { @@ -11,6 +33,161 @@ public static void initMills() { JavaDSLMill.globalScope().clear(); CD4CodeMill.init(); CD4CodeMill.globalScope().clear(); + BuiltInTypes.addBuiltInTypes(CD4CodeMill.globalScope()); + UnderspecifiedPlaceholderType.addPlaceholderType(CD4CodeMill.globalScope()); Log.init(); } + + protected static String readFileContent(Path outputPath, String filename) { + Path filePath = findFile(outputPath, filename); + assertTrue(Files.exists(filePath), () -> "Expected generated file: " + filePath); + try { + return Files.readString(filePath, StandardCharsets.UTF_8); + } catch (IOException e) { + fail("Failed to read file: " + filePath + " (" + e.getMessage() + ")"); + return ""; + } + } + + private static Path findFile(Path outputPath, String filename) { + Path direct = outputPath.resolve(filename); + if (Files.exists(direct)) { + return direct; + } + try (Stream paths = Files.walk(outputPath)) { + return paths + .filter(Files::isRegularFile) + .filter(path -> path.getFileName().toString().equals(filename)) + .findFirst() + .orElse(direct); + } catch (IOException e) { + return direct; + } + } + + protected static Set generatedFileNames(Path outputPath) { + try (Stream files = Files.walk(outputPath)) { + return files + .filter(Files::isRegularFile) + .map(path -> path.getFileName().toString()) + .collect(Collectors.toSet()); + } catch (IOException e) { + fail("Failed to list generated files in " + outputPath + ": " + e.getMessage()); + return Set.of(); + } + } + + protected static List generatedJavaFiles(Path sourceDir) { + try (Stream files = Files.walk(sourceDir)) { + return files + .filter(path -> path.toString().endsWith(".java")) + .sorted() + .collect(Collectors.toCollection(ArrayList::new)); + } catch (IOException e) { + fail("Failed to list generated Java files in " + sourceDir + ": " + e.getMessage()); + return List.of(); + } + } + + protected static List generatedJavaFilesRecursively(Path sourceDir) { + assertTrue(Files.isDirectory(sourceDir), () -> "Expected Java source directory: " + sourceDir); + try (Stream files = Files.walk(sourceDir)) { + return files + .filter(Files::isRegularFile) + .filter(path -> path.toString().endsWith(".java")) + .sorted() + .collect(Collectors.toCollection(ArrayList::new)); + } catch (IOException e) { + fail("Failed to list generated Java files in " + sourceDir + ": " + e.getMessage()); + return List.of(); + } + } + + protected static void assertNoAdapterMetadata(Path outputPath) { + for (Path file : generatedJavaFilesRecursively(outputPath)) { + try { + String content = Files.readString(file, StandardCharsets.UTF_8); + assertFalse(content.contains("@Adapt"), () -> "Adapter annotation leaked into " + file); + assertFalse( + content.contains("de.monticore.codeAdaption.utils.Adapt"), + () -> "Adapter import leaked into " + file); + } catch (IOException e) { + fail("Failed to inspect generated Java metadata in " + file + ": " + e.getMessage()); + } + } + } + + protected static void assertGeneratedJavaCompiles(Path sourceDir) { + assertGeneratedJavaCompiles(generatedJavaFiles(sourceDir)); + } + + protected static void assertGeneratedJavaCompiles(List javaFiles) { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + assertNotNull(compiler, "Tests must run on a JDK with javax.tools.JavaCompiler available"); + + Path classesDir = + javaFiles.isEmpty() + ? Path.of("target", "adapter", "_compile") + : javaFiles.get(0).toAbsolutePath().getParent().resolve("_compile"); + try { + deleteRecursively(classesDir); + Files.createDirectories(classesDir); + StringWriter compilerOutput = new StringWriter(); + try (StandardJavaFileManager fileManager = + compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8)) { + Iterable compilationUnits = + fileManager.getJavaFileObjectsFromPaths(javaFiles); + List options = + List.of( + "-d", + classesDir.toString(), + "-classpath", + System.getProperty("java.class.path")); + Boolean compiled = + compiler.getTask(compilerOutput, fileManager, null, options, null, compilationUnits) + .call(); + assertEquals( + Boolean.TRUE, + compiled, + () -> "Generated Java does not compile" + System.lineSeparator() + + compilerOutput); + } + } catch (IOException e) { + fail("Failed to compile generated Java: " + e.getMessage()); + } finally { + deleteRecursively(classesDir); + } + } + + protected static void deleteRecursively(Path path) { + if (path == null || !Files.exists(path)) { + return; + } + try (Stream paths = Files.walk(path)) { + for (Path current : paths.sorted(Comparator.reverseOrder()).toList()) { + deletePathWithRetry(current); + } + } catch (IOException e) { + fail("Failed to delete path recursively: " + path + " (" + e.getMessage() + ")"); + } + } + + protected static void deletePathWithRetry(Path path) { + IOException last = null; + for (int attempt = 0; attempt < 5; attempt++) { + try { + Files.deleteIfExists(path); + return; + } catch (IOException e) { + last = e; + try { + Thread.sleep(100L * (attempt + 1)); + } catch (InterruptedException interrupted) { + Thread.currentThread().interrupt(); + fail("Interrupted while deleting " + path + ": " + interrupted.getMessage()); + } + } + } + fail("Failed to delete path: " + path + " (" + (last == null ? "unknown" : last.getMessage()) + ")"); + } } diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/BuilderPatternAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/BuilderPatternAdapterTest.java new file mode 100644 index 00000000..9af7d587 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/BuilderPatternAdapterTest.java @@ -0,0 +1,163 @@ +package de.monticore.codeAdaption; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static org.junit.jupiter.api.Assertions.*; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.updater.CodeUpdaterMill; +import de.monticore.codeAdaption.updater.spoonUpdater.SpoonUpdater; +import de.monticore.codeAdaption.utils.AdapterParam; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class BuilderPatternAdapterTest extends AdapterAbstractTest { + private final String resourcesPath = + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/"; + private final File refCD = new File(resourcesPath + "Reference.cd"); + private final File concreteCD = new File(resourcesPath + "Concrete.cd"); + private final Path concreteCodePath = Path.of(resourcesPath + "concrete"); + private final Path adapterCodePath = Path.of(resourcesPath + "adapter"); + private final Path outputPath = Path.of("target/adapter/builder_pattern"); + + private Set confParameters; + private Set adapterParams; + + @BeforeEach + public void setup() { + initMills(); + deleteRecursively(outputPath); + confParameters = Set.of(NAME_MAPPING, INHERITANCE, STEREOTYPE_MAPPING, STRICT_PARAMETER_ORDER); + adapterParams = Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + } + + @Test + @DisplayName("Builder Pattern: Adapt Builder to create PersonBuilder and TaskBuilder") + public void testBuilderPatternAdaptation() { + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow( + () -> + adapter.adapt( + refCD, concreteCD, Set.of("buildPat"), adapterCodePath, concreteCodePath, outputPath)); + + assertEquals( + Set.of("PersonBuilder.java", "TaskBuilder.java", "Person.java", "Task.java"), + generatedFileNames(outputPath)); + assertNoAdapterMetadata(outputPath); + assertGeneratedJavaCompiles(outputPath); + + String personBuilderContent = simplifyGeneratedReferences(readFileContent(outputPath, "PersonBuilder.java")); + String taskBuilderContent = simplifyGeneratedReferences(readFileContent(outputPath, "TaskBuilder.java")); + + assertTrue(personBuilderContent.contains("public class PersonBuilder")); + assertTrue(personBuilderContent.contains("public PersonBuilder setName(String name)")); + assertTrue(personBuilderContent.contains("public PersonBuilder setAge(int age)")); + assertTrue(personBuilderContent.contains("public PersonBuilder setEmail(String email)")); + assertTrue(personBuilderContent.contains("public PersonBuilder setPhone(String phone)")); + assertTrue(personBuilderContent.contains("public PersonBuilder setTags(List tags)")); + assertTrue(personBuilderContent.contains("public Person build()")); + assertTrue(personBuilderContent.contains("return this;")); + + assertTrue(taskBuilderContent.contains("public class TaskBuilder")); + assertTrue(taskBuilderContent.contains("public TaskBuilder setId(int id)")); + assertTrue(taskBuilderContent.contains("public TaskBuilder setTitle(String title)")); + assertTrue(taskBuilderContent.contains("public TaskBuilder setDescription(String description)")); + assertTrue(taskBuilderContent.contains("public TaskBuilder setStatus(String status)")); + assertTrue(taskBuilderContent.contains("public TaskBuilder setDueDate(Date dueDate)")); + assertTrue(taskBuilderContent.contains("public TaskBuilder setAssignee(String assignee)")); + assertTrue(taskBuilderContent.contains("public Task build()")); + assertTrue(taskBuilderContent.contains("return this;")); + + assertTrue(personBuilderContent.contains("String nameField")); + assertTrue(personBuilderContent.contains("int ageField")); + assertTrue(personBuilderContent.contains("String emailField")); + assertTrue(personBuilderContent.contains("String phoneField")); + assertTrue(personBuilderContent.contains("List tagsField")); + + assertTrue(taskBuilderContent.contains("int idField")); + assertTrue(taskBuilderContent.contains("String titleField")); + assertTrue(taskBuilderContent.contains("String descriptionField")); + assertTrue(taskBuilderContent.contains("String statusField")); + assertTrue(taskBuilderContent.contains("Date dueDateField")); + assertTrue(taskBuilderContent.contains("String assigneeField")); + + assertTrue(personBuilderContent.contains("this.nameField = name")); + assertTrue(personBuilderContent.contains("this.ageField = age")); + + assertTrue(taskBuilderContent.contains("this.idField = id")); + assertTrue(taskBuilderContent.contains("this.titleField = title")); + + assertTrue(personBuilderContent.contains("new Person(")); + assertTrue(taskBuilderContent.contains("new Task(")); + assertTrue( + personBuilderContent.contains( + "return new Person(this.nameField, this.ageField, this.emailField, this.phoneField, this.tagsField);")); + assertTrue( + taskBuilderContent + .contains( + "return new Task(this.idField, this.titleField, this.descriptionField, this.statusField, this.dueDateField, this.assigneeField);")); + assertFalse(personBuilderContent.contains("class Builder")); + assertFalse(taskBuilderContent.contains("class Builder")); + + String personContent = simplifyGeneratedReferences(readFileContent(outputPath, "Person.java")); + String taskContent = simplifyGeneratedReferences(readFileContent(outputPath, "Task.java")); + + assertTrue(personContent.contains("public class Person")); + assertTrue(personContent.contains("String name")); + assertTrue(personContent.contains("int age")); + + assertTrue(taskContent.contains("public class Task")); + assertTrue(taskContent.contains("int id")); + assertTrue(taskContent.contains("String title")); + } + + @Test + @DisplayName("Builder Pattern: configured updater provider is used across isolated passes") + public void usesConfiguredUpdaterProvider() { + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + Path millOutputPath = outputPath.resolve("mill"); + AtomicInteger createdUpdaters = new AtomicInteger(); + CodeUpdaterMill.init( + () -> { + createdUpdaters.incrementAndGet(); + return new SpoonUpdater(); + }); + + try { + assertDoesNotThrow( + () -> + adapter.adapt( + refCD, + concreteCD, + Set.of("buildPat"), + adapterCodePath, + concreteCodePath, + millOutputPath)); + + assertTrue( + createdUpdaters.get() > 1, + "Adaptation should obtain separate updater instances for independent passes"); + assertTrue(generatedFileNames(millOutputPath).contains("PersonBuilder.java")); + assertTrue(generatedFileNames(millOutputPath).contains("TaskBuilder.java")); + assertGeneratedJavaCompiles(millOutputPath); + } finally { + CodeUpdaterMill.init(); + } + } + + private static String simplifyGeneratedReferences(String content) { + return content + .replace("de.monticore.codeAdaption.evaluation.testcase_6_builder_pattern.", "") + .replace("java.lang.", "") + .replace("java.util.", ""); + } +} + diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CDConcretizationAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CDConcretizationAdapterTest.java new file mode 100644 index 00000000..eef411a2 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CDConcretizationAdapterTest.java @@ -0,0 +1,478 @@ +package de.monticore.codeAdaption; + +import static de.monticore.cdconformance.CDConfParameter.ADAPTED_NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.ALLOW_ADDITIONAL_PARAMETERS; +import static de.monticore.cdconformance.CDConfParameter.ALLOW_CARD_RESTRICTION; +import static de.monticore.cdconformance.CDConfParameter.INHERITANCE; +import static de.monticore.cdconformance.CDConfParameter.METHOD_OVERLOADING; +import static de.monticore.cdconformance.CDConfParameter.NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.SRC_TARGET_ASSOC_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STEREOTYPE_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STRICT_PARAMETER_ORDER; +import static de.monticore.codeAdaption.utils.AdapterParam.ANNOTATION_MATCHING; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_TYPE; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_VAR; +import static de.monticore.codeAdaption.utils.AdapterParam.NAME_MATCHING; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.testutil.CDConcretizationTestCase; +import de.monticore.codeAdaption.testutil.CDConcretizationTestCases; +import de.monticore.codeAdaption.testutil.CDConcretizationFixtureWorkspace; +import de.monticore.codeAdaption.testutil.GeneratedJavaStructureOracle; +import de.monticore.codeAdaption.utils.AdapterParam; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.se_rwth.commons.logging.LogStub; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; + +public class CDConcretizationAdapterTest extends AdapterAbstractTest { + + private Set confParameters; + private Set adapterParams; + + @TempDir Path temporaryDirectory; + + @BeforeEach + public void setup() { + LogStub.init(); + initMills(); + adapterParams = + Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + } + + static Stream testCases() { + return CDConcretizationTestCases.enabledCases().stream(); + } + + static Stream expectedFailureCases() { + return CDConcretizationTestCases.expectedFailureCases().stream(); + } + + static Stream unsupportedCases() { + return CDConcretizationTestCases.unsupportedCases().stream(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("testCases") + void adaptsWithConcretizationCompleter(CDConcretizationTestCase testCase) { + CDConcretizationTestCase materializedTestCase = + CDConcretizationFixtureWorkspace.materialize(testCase); + confParameters = defaultConformanceParams(materializedTestCase.strictParameterOrder()); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + cleanPreviousOutput(materializedTestCase); + + assertDoesNotThrow( + () -> + adapter.adapt( + materializedTestCase.refCd().toFile(), + materializedTestCase.concCd().toFile(), + materializedTestCase.mappings(), + materializedTestCase.adapterPath(), + materializedTestCase.concretePath(), + materializedTestCase.outputPath(), + true, + true), + () -> "Adaptation failed for " + materializedTestCase.displayName()); + + List javaFiles = + generatedJavaFiles(materializedTestCase, materializedTestCase.outputPath()); + assertFalse( + javaFiles.isEmpty(), + () -> "No Java output generated for " + materializedTestCase.displayName()); + assertNoWildcardJdkImports(materializedTestCase, javaFiles); + assertNoAdaptMetadata(materializedTestCase, javaFiles); + CDConcretizationTestCases.expectedOutputModel(testCase) + .ifPresentOrElse( + expected -> + GeneratedJavaStructureOracle.assertMatches( + testCase.concCd(), expected, javaFiles), + () -> + assertTrue( + CDConcretizationTestCases.noExpectedOutputReason(testCase).isPresent(), + () -> "No expected-output model or documented reason for " + testCase)); + + assertGeneratedJavaCompiles(compilationSources(javaFiles, materializedTestCase)); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("expectedFailureCases") + void rejectsInvalidConcretizationWithoutReplacingOutput(CDConcretizationTestCase testCase) + throws IOException { + assertRejectedWithoutReplacingOutput(testCase); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("unsupportedCases") + void rejectsDocumentedUpstreamLimitationWithoutReplacingOutput( + CDConcretizationTestCase testCase) throws IOException { + assertFalse(CDConcretizationTestCases.unsupportedReason(testCase).isBlank()); + assertRejectedWithoutReplacingOutput(testCase); + } + + @Test + void compilationOracleRejectsUnadaptedReferenceType() throws IOException { + CDConcretizationTestCase testCase = oracleTestCase("stale-reference"); + write(testCase.refCd(), "classdiagram Reference { class ReferenceType; }"); + write(testCase.concCd(), "classdiagram Concrete { class ConcreteType; }"); + Path adapted = + write( + testCase.outputPath().resolve("adapted/UsesReference.java"), + "package adapted; public class UsesReference { ReferenceType value; }"); + + List sources = compilationSources(List.of(adapted), testCase); + + assertFalse( + sources.stream() + .anyMatch(path -> path.getFileName().toString().equals("ReferenceType.java"))); + assertThrows(AssertionError.class, () -> assertGeneratedJavaCompiles(sources)); + } + + @ParameterizedTest(name = "adapted package {0} compiles: {1}") + @CsvSource({"wrong, false", "expected, true"}) + void compilationOracleResolvesOriginalConcreteTypeFromExpectedPackage( + String adaptedPackage, boolean compiles) throws IOException { + CDConcretizationTestCase testCase = oracleTestCase("concrete-type-" + adaptedPackage); + write(testCase.refCd(), "classdiagram Reference { class ReferenceType; }"); + write(testCase.concCd(), "classdiagram Concrete { class ConcreteType; }"); + write( + testCase.concretePath().resolve("Anchor.java"), + "package expected;\npublic class Anchor {}"); + Path adapted = + write( + testCase.outputPath().resolve(adaptedPackage + "/UsesConcrete.java"), + "package " + + adaptedPackage + + "; public class UsesConcrete { ConcreteType value; }"); + + List sources = compilationSources(List.of(adapted), testCase); + + assertTrue( + sources.stream() + .anyMatch( + path -> + path.toString() + .replace('\\', '/') + .endsWith("/expected/ConcreteType.java"))); + if (compiles) { + assertDoesNotThrow(() -> assertGeneratedJavaCompiles(sources)); + } else { + assertThrows(AssertionError.class, () -> assertGeneratedJavaCompiles(sources)); + } + } + + @Test + void structuralOracleRejectsCompilableOutputWithMissingExpectedMember() throws IOException { + Path original = temporaryDirectory.resolve("Original.cd"); + Path expected = temporaryDirectory.resolve("ExpectedOut.cd"); + write(original, "classdiagram Original { class Sample { int present; } }"); + write(expected, "classdiagram Expected { class Sample { int present; int missing; } }"); + Path generated = + write( + temporaryDirectory.resolve("generated/Sample.java"), + "public class Sample { int present; }"); + + assertThrows( + AssertionError.class, + () -> GeneratedJavaStructureOracle.assertMatches(original, expected, List.of(generated))); + } + + private void assertRejectedWithoutReplacingOutput(CDConcretizationTestCase testCase) + throws IOException { + CDConcretizationTestCase materializedTestCase = + CDConcretizationFixtureWorkspace.materialize(testCase); + confParameters = defaultConformanceParams(materializedTestCase.strictParameterOrder()); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + cleanPreviousOutput(materializedTestCase); + Files.createDirectories(materializedTestCase.outputPath()); + Path marker = materializedTestCase.outputPath().resolve("existing-output.txt"); + Files.writeString(marker, "preserve", StandardCharsets.UTF_8); + + assertThrows( + IllegalStateException.class, + () -> + adapter.adapt( + materializedTestCase.refCd().toFile(), + materializedTestCase.concCd().toFile(), + materializedTestCase.mappings(), + materializedTestCase.adapterPath(), + materializedTestCase.concretePath(), + materializedTestCase.outputPath(), + true, + true)); + assertTrue(Files.exists(marker), "A failed run must preserve the previous output"); + assertEquals("preserve", Files.readString(marker, StandardCharsets.UTF_8)); + } + + private static Set defaultConformanceParams(boolean strictParameterOrder) { + Set params = new LinkedHashSet<>(); + params.add(STEREOTYPE_MAPPING); + params.add(NAME_MAPPING); + params.add(SRC_TARGET_ASSOC_MAPPING); + params.add(INHERITANCE); + params.add(ALLOW_CARD_RESTRICTION); + params.add(METHOD_OVERLOADING); + params.add(ADAPTED_NAME_MAPPING); + params.add(ALLOW_ADDITIONAL_PARAMETERS); + if (strictParameterOrder) { + params.add(STRICT_PARAMETER_ORDER); + } + return params; + } + + private static void cleanPreviousOutput(CDConcretizationTestCase testCase) { + deleteOutputPath(testCase.outputPath()); + deleteOutputPath(testCase.outputPath().resolveSibling(testCase.outputPath().getFileName() + "_formatted")); + deleteOutputPath(testCase.outputPath().resolveSibling(testCase.outputPath().getFileName() + "_generated")); + deleteOutputPath( + testCase.outputPath().resolveSibling(testCase.outputPath().getFileName() + "_compile_stubs")); + } + + private static List compilationSources( + List adaptedJava, CDConcretizationTestCase testCase) { + Map sourcesByType = new LinkedHashMap<>(); + adaptedJava.forEach(path -> sourcesByType.put(sourceTypeName(path), path)); + Path concretePath = testCase.concretePath(); + if (Files.isDirectory(concretePath)) { + generatedJavaFilesRecursively(concretePath).forEach( + path -> sourcesByType.putIfAbsent(sourceTypeName(path), path)); + } + addConcreteModelStubs(testCase, sourcesByType); + return new ArrayList<>(sourcesByType.values()); + } + + private static void addConcreteModelStubs( + CDConcretizationTestCase testCase, Map sourcesByType) { + Map declarations = new LinkedHashMap<>(); + initMills(); + addModelDeclarations(JavaLoader.parseCD(testCase.concCd().toString()), declarations); + + Set concretePackages = + Files.isDirectory(testCase.concretePath()) + ? generatedJavaFilesRecursively(testCase.concretePath()).stream() + .map(CDConcretizationAdapterTest::packageName) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)) + : Set.of(); + if (concretePackages.size() != 1) { + return; + } + String packageName = concretePackages.iterator().next(); + Path stubRoot = + testCase + .outputPath() + .resolveSibling(testCase.outputPath().getFileName() + "_compile_stubs"); + Map generatedStubs = new LinkedHashMap<>(); + for (Map.Entry declaration : declarations.entrySet()) { + String qualifiedTypeName = qualify(packageName, declaration.getKey()); + if (sourcesByType.containsKey(qualifiedTypeName)) { + continue; + } + Path packageDirectory = + packageName.isBlank() + ? stubRoot + : stubRoot.resolve(packageName.replace('.', java.io.File.separatorChar)); + Path source = packageDirectory.resolve(declaration.getKey() + ".java"); + Path conflict = generatedStubs.putIfAbsent(qualifiedTypeName, source); + if (conflict != null && !conflict.equals(source)) { + throw new IllegalStateException( + "Conflicting compile stubs for " + + qualifiedTypeName + + ": " + + conflict + + " and " + + source); + } + String body = + declaration.getValue().equals("enum") + ? "public enum " + declaration.getKey() + " {;}" + : "public " + declaration.getValue() + " " + declaration.getKey() + " {}"; + String content = + (packageName.isBlank() ? "" : "package " + packageName + ";\n") + body + "\n"; + try { + Files.createDirectories(packageDirectory); + Files.writeString(source, content, StandardCharsets.UTF_8); + } catch (IOException exception) { + throw new IllegalStateException("Failed to write compile stub " + source, exception); + } + sourcesByType.put(qualifiedTypeName, source); + } + } + + private static void addModelDeclarations( + ASTCDCompilationUnit cd, Map declarations) { + cd + .getCDDefinition() + .getCDClassesList() + .forEach(type -> addModelDeclaration(declarations, type.getName(), "class")); + cd + .getCDDefinition() + .getCDInterfacesList() + .forEach(type -> addModelDeclaration(declarations, type.getName(), "interface")); + cd + .getCDDefinition() + .getCDEnumsList() + .forEach(type -> addModelDeclaration(declarations, type.getName(), "enum")); + } + + private static void addModelDeclaration( + Map declarations, String typeName, String kind) { + String conflict = declarations.putIfAbsent(typeName, kind); + if (conflict != null) { + throw new IllegalStateException( + "Conflicting concrete model declarations for " + + typeName + + ": " + + conflict + + " and " + + kind); + } + } + + private static String sourceTypeName(Path source) { + String fileName = source.getFileName().toString(); + String simpleName = fileName.substring(0, fileName.length() - ".java".length()); + return qualify(packageName(source), simpleName); + } + + private static String qualify(String packageName, String simpleName) { + return packageName.isBlank() ? simpleName : packageName + "." + simpleName; + } + + private static String packageName(Path source) { + try { + String packageName = ""; + for (String line : Files.readAllLines(source, StandardCharsets.UTF_8)) { + String trimmed = line.strip(); + if (trimmed.startsWith("package ") && trimmed.endsWith(";")) { + packageName = trimmed.substring("package ".length(), trimmed.length() - 1).strip(); + break; + } + } + return packageName; + } catch (IOException exception) { + throw new IllegalStateException("Failed to inspect Java source " + source, exception); + } + } + + private static void deleteOutputPath(java.nio.file.Path path) { + if (!path.startsWith(java.nio.file.Path.of(CDConcretizationTestCase.OUTPUT_ROOT))) { + throw new IllegalArgumentException("Refusing to delete path outside test output root: " + path); + } + deleteRecursively(path); + } + + private static List generatedJavaFiles( + CDConcretizationTestCase testCase, Path outputPath) { + try { + return generatedJavaFilesRecursively(outputPath).stream() + .filter(CDConcretizationAdapterTest::isFinalOutputFile) + .sorted() + .toList(); + } catch (RuntimeException e) { + throw new IllegalStateException("Failed to inspect generated output for " + testCase.displayName(), e); + } + } + + private static boolean isFinalOutputFile(java.nio.file.Path path) { + for (java.nio.file.Path part : path) { + String name = part.toString(); + if (name.startsWith("_temp_") || name.endsWith("_formatted")) { + return false; + } + } + return true; + } + + private static void assertNoAdaptMetadata( + CDConcretizationTestCase testCase, List javaFiles) { + List filesWithMetadata = + javaFiles.stream() + .filter(CDConcretizationAdapterTest::containsAdaptMetadata) + .toList(); + + assertTrue( + filesWithMetadata.isEmpty(), + () -> "Generated output still contains @Adapt metadata for " + + testCase.displayName() + + ": " + + filesWithMetadata); + } + + private static boolean containsAdaptMetadata(java.nio.file.Path path) { + try { + String source = java.nio.file.Files.readString(path); + return source.contains("@Adapt") + || source.contains("import de.monticore.codeAdaption.utils.Adapt"); + } catch (IOException e) { + throw new IllegalStateException("Failed to read generated Java file " + path, e); + } + } + + private static void assertNoWildcardJdkImports( + CDConcretizationTestCase testCase, List javaFiles) { + List filesWithWildcards = + javaFiles.stream() + .filter(CDConcretizationAdapterTest::containsWildcardJdkImport) + .toList(); + + assertTrue( + filesWithWildcards.isEmpty(), + () -> "Generated output contains wildcard JDK imports for " + + testCase.displayName() + + ": " + + filesWithWildcards); + } + + private static boolean containsWildcardJdkImport(java.nio.file.Path path) { + try { + String source = java.nio.file.Files.readString(path); + return source.contains("import java.util.*;") || source.contains("import java.time.*;"); + } catch (IOException e) { + throw new IllegalStateException("Failed to read generated Java file " + path, e); + } + } + + private CDConcretizationTestCase oracleTestCase(String name) throws IOException { + Path root = temporaryDirectory.resolve(name); + Files.createDirectories(root.resolve("concrete")); + Files.createDirectories(root.resolve("output")); + return new CDConcretizationTestCase( + name, + name, + root.resolve("Reference.cd"), + root.resolve("Concrete.cd"), + root.resolve("adapter"), + root.resolve("concrete"), + root.resolve("output"), + Set.of("ref"), + false, + true); + } + + private static Path write(Path path, String content) throws IOException { + Files.createDirectories(path.getParent()); + Files.writeString(path, content + System.lineSeparator(), StandardCharsets.UTF_8); + return path; + } + +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterCleanupTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterCleanupTest.java new file mode 100644 index 00000000..d54732e8 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterCleanupTest.java @@ -0,0 +1,54 @@ +package de.monticore.codeAdaption; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class CodeAdapterCleanupTest { + + @TempDir Path output; + + @Test + void cleanCodePreservesPackagePathsAndRemovesOnlyToolAdaptAnnotations() throws IOException { + Path first = output.resolve("a/User.java"); + Path second = output.resolve("b/User.java"); + Files.createDirectories(first.getParent()); + Files.createDirectories(second.getParent()); + Files.writeString( + first, + """ + package a; + import de.monticore.codeAdaption.utils.Adapt; + + @Adapt(ignore = true) + @demo.local.Adapt(ignore = true) + public class User {} + """); + Files.writeString( + second, + """ + package b; + import de.monticore.codeAdaption.utils.Adapt; + + @Adapt(ignore = true) + public class User {} + """); + + new OutputCodeService().cleanCode(output); + + assertTrue(Files.exists(first)); + assertTrue(Files.exists(second)); + assertFalse(Files.exists(output.resolve("User.java"))); + String firstCleaned = Files.readString(first); + String secondCleaned = Files.readString(second); + assertTrue(firstCleaned.contains("@demo.local.Adapt"), firstCleaned); + assertFalse(firstCleaned.contains("import de.monticore.codeAdaption.utils.Adapt")); + assertFalse(secondCleaned.contains("import de.monticore.codeAdaption.utils.Adapt")); + assertFalse(secondCleaned.contains("@Adapt")); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterSafetyTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterSafetyTest.java new file mode 100644 index 00000000..c65f2ce6 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterSafetyTest.java @@ -0,0 +1,83 @@ +package de.monticore.codeAdaption; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.codeAdaption.utils.JavaLoader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class CodeAdapterSafetyTest { + + @TempDir Path tempDir; + + @ParameterizedTest(name = "rejects path containment: {0}") + @ValueSource(strings = {"output-inside-reference", "reference-inside-output"}) + void rejectsOverlappingReferenceAndOutputPaths(String scenario) { + Path reference = tempDir.resolve("reference"); + Path output = tempDir.resolve("output"); + if ("output-inside-reference".equals(scenario)) { + output = reference.resolve("generated"); + } else { + reference = output.resolve("reference"); + } + Path concrete = tempDir.resolve("concrete"); + Path finalReference = reference; + Path finalOutput = output; + + assertThrows( + IllegalArgumentException.class, + () -> CodeAdapter.validatePaths(finalReference, concrete, finalOutput)); + } + + @Test + void rejectsClassDiagramInsideOutput() { + Path output = tempDir.resolve("output"); + AdaptationWorkspace workspace = + new AdaptationWorkspace( + tempDir.resolve("reference"), tempDir.resolve("concrete"), output); + + assertThrows( + IllegalArgumentException.class, + () -> + workspace.validateReadOnlyInput( + output.resolve("Reference.cd"), "reference class diagram")); + } + + @Test + void refusesToDeleteFilesystemRoot() { + Path root = tempDir.toAbsolutePath().getRoot(); + + assertThrows(IllegalArgumentException.class, () -> JavaLoader.removeDirectory(root)); + } + + @Test + void missingJavaSourceDirectoryIsAnError() { + assertThrows( + IllegalArgumentException.class, + () -> JavaLoader.readJavaCode(tempDir.resolve("does-not-exist"))); + } + + @Test + void rejectsDifferentConcreteFilesWithTheSamePackageTarget() throws IOException { + Path concrete = tempDir.resolve("concrete"); + Path first = concrete.resolve("first/User.java"); + Path second = concrete.resolve("second/User.java"); + Files.createDirectories(first.getParent()); + Files.createDirectories(second.getParent()); + Files.writeString(first, "package p; class User { int first; }"); + Files.writeString(second, "package p; class User { int second; }"); + + IllegalStateException exception = + assertThrows( + IllegalStateException.class, + () -> new OutputCodeService().copyConcreteFiles(concrete, tempDir.resolve("output"))); + + assertTrue(exception.getMessage().contains("both target")); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterTest.java index 78099f19..5dcd7448 100644 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterTest.java +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterTest.java @@ -5,10 +5,8 @@ import de.monticore.cdconformance.CDConfParameter; import de.monticore.codeAdaption.utils.AdapterParam; -import de.monticore.codeAdaption.utils.JavaLoader; import java.io.File; import java.nio.file.Path; -import java.util.Optional; import java.util.Set; import org.junit.jupiter.api.*; @@ -37,8 +35,9 @@ public void testAdaptionWithName() { adapter.adapt(REF_CD, CON_CD, mappings, Path.of(baseDir + "adapter/name"), conHwc, outputPath); - String student = readFileWithoutSpace(outputPath, "Student.java"); - Assertions.assertEquals("publicclassStudent{StringstudentId;}", student); + String student = readFileContent(outputPath, "Student.java"); + Assertions.assertTrue(student.contains("public class Student")); + Assertions.assertTrue(student.contains("String studentId;")); } @Test @@ -49,10 +48,12 @@ public void testAdaptionWithInfix() { adapter.adapt(REF_CD, CON_CD, mappings, Path.of(baseDir + "adapter/infix"), conHwc, outputPath); - String studentBuilder = readFileWithoutSpace(outputPath, "StudentBuilder.java"); - Assertions.assertEquals( - "publicclassStudentBuilder{protectedStringstudentId;publicStudentBuildersetStudentId(Stringid){Studentstudent=newStudent();}}", - studentBuilder); + String studentBuilder = readFileContent(outputPath, "StudentBuilder.java"); + Assertions.assertTrue(studentBuilder.contains("public class StudentBuilder")); + Assertions.assertTrue(studentBuilder.contains("protected String studentId;")); + Assertions.assertTrue( + studentBuilder.contains("public StudentBuilder setStudentId(String id)")); + Assertions.assertTrue(studentBuilder.contains("Student student = new Student();")); } @Test @@ -63,10 +64,16 @@ public void testAdaptionWithAnnotation() { adapter.adapt(REF_CD, CON_CD, mappings, Path.of(baseDir + "adapter/annot"), conHwc, outputPath); - String studentRepository = readFileWithoutSpace(outputPath, "StudentRepository.java"); - Assertions.assertEquals( - "importjava.util.*;publicclassStudentRepositoryextendsRepository{privateSetstudentSet=newHashSet<>();publicOptionalfindStudentByStudentId(Stringid){returnOptional.empty();}publicListgetAllStudentSortedByStudentId(){ListstudentList=newArrayList<>();}publicvoidstore(Studentstudent){studentSet.add(student);}}", - studentRepository); + String studentRepository = readFileContent(outputPath, "StudentRepository.java"); + Assertions.assertTrue( + studentRepository.contains("public class StudentRepository extends Repository")); + Assertions.assertTrue( + studentRepository.contains("private Set studentSet = new HashSet<>();")); + Assertions.assertTrue( + studentRepository.contains("public Optional findStudentByStudentId(String id)")); + Assertions.assertTrue( + studentRepository.contains("public List getAllStudentSortedByStudentId()")); + Assertions.assertTrue(studentRepository.contains("public void store(Student student)")); } @Test @@ -79,19 +86,12 @@ public void testAdaptionWithAllMatchingStrategy() { adapter.adapt( REF_CD, CON_CD, mappings, Path.of(baseDir + "adapter/compose"), conHwc, outputPath); - String studentRepository = readFileWithoutSpace(outputPath, "StudentRepository.java"); - - Assertions.assertEquals( - "importjava.util.*;publicclassStudentRepositoryextendsRepository{privateSetstudentSet=newHashSet<>();publicOptionalfindStudentByStudentId(Stringid){returnOptional.empty();}publicListgetAllStudentSortedByStudentId(){ListstudentList=newArrayList<>();}publicvoidstore(Studentstudent){studentSet.add(student);}}", - studentRepository); - } - - protected String readFileWithoutSpace(Path dir, String filename) { - Optional file = - JavaLoader.readJavaFile(dir).stream() - .filter(f -> f.getName().endsWith(filename)) - .findFirst(); - Assertions.assertTrue(file.isPresent()); - return JavaLoader.readFileContent(file.get()).replaceAll("\\s+", ""); + String studentRepository = readFileContent(outputPath, "StudentRepository.java"); + Assertions.assertTrue( + studentRepository.contains("public class StudentRepository extends Repository")); + Assertions.assertTrue(studentRepository.contains("return Optional.empty();")); + Assertions.assertTrue( + studentRepository.contains("List studentList = new ArrayList<>();")); + Assertions.assertTrue(studentRepository.contains("studentSet.add(student);")); } } diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterToolTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterToolTest.java index f12b2233..c869c6ef 100644 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterToolTest.java +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterToolTest.java @@ -1,13 +1,62 @@ package de.monticore.codeAdaption; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class CodeAdapterToolTest { +class CodeAdapterToolTest extends AdapterAbstractTest { + + private static final Path RESOURCES = + Path.of("src/test/resources/de/monticore/codeAdaption"); + + @BeforeEach + void setUp() { + initMills(); + } @Test - public void test() { - String cmd = "-i University.cd --reference UserRole.cd --rc code"; - // String cmd = "java -jar AdapterTool.jar -i University.cd --reference UserRole.cd --rc code" - // ; + void commandLineInvocationProducesAdaptedOutput() { + Path output = Path.of("target/adapter/cli"); + deleteRecursively(output); + + int exitCode = + new CodeAdapterTool() + .execute( + new String[] { + "--reference", + RESOURCES.resolve("App.cd").toString(), + "--concrete", + RESOURCES.resolve("UniApp.cd").toString(), + "--reference-code", + RESOURCES.resolve("adapter/name").toString(), + "--concrete-code", + RESOURCES.resolve("hwc").toString(), + "--output", + output.toString(), + "--mapping", + "ref", + "--matching", + "name" + }); + + assertEquals(0, exitCode); + assertTrue(Files.exists(findGeneratedFile(output, "Student.java"))); + assertGeneratedJavaCompiles(output); + } + + private static Path findGeneratedFile(Path output, String fileName) { + try (var files = Files.walk(output)) { + return files + .filter(Files::isRegularFile) + .filter(path -> path.getFileName().toString().equals(fileName)) + .findFirst() + .orElse(output.resolve(fileName)); + } catch (java.io.IOException exception) { + throw new IllegalStateException("Failed to inspect CLI output", exception); + } } } diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/ControllerWorkerAdapterReversedTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/ControllerWorkerAdapterReversedTest.java new file mode 100644 index 00000000..678f09c5 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/ControllerWorkerAdapterReversedTest.java @@ -0,0 +1,79 @@ +package de.monticore.codeAdaption; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.AdapterParam; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static org.junit.jupiter.api.Assertions.*; + +public class ControllerWorkerAdapterReversedTest extends AdapterAbstractTest { + private final String resourcesPath = + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/"; + private final File refCD = new File(resourcesPath + "Reference.cd"); + private final File concreteCD = new File(resourcesPath + "Concrete.cd"); + private final Path refCodePath = Path.of(resourcesPath + "concrete"); + private final Path adapterCodePath = Path.of(resourcesPath + "adapter"); + private final Path outputPath = Path.of("target/adapter/controller_worker_observer_reversed"); + + private Set confParameters; + private Set adapterParams; + + @BeforeEach + public void setup() { + initMills(); + confParameters = Set.of(NAME_MAPPING, INHERITANCE, STEREOTYPE_MAPPING, STRICT_PARAMETER_ORDER); + adapterParams = Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + } + + @Test + @DisplayName("Builder + Observer Patterns: Adapt Controller and Workers") + public void testControllerWorkerAdaptation() { + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow(() -> { + adapter.adapt(refCD, concreteCD, Set.of("buildPat", "observer"), adapterCodePath, refCodePath, outputPath); + }); + + Set generatedFiles = generatedFileNames(outputPath); + assertTrue(generatedFiles.contains("ControllerBuilder.java")); + assertTrue(generatedFiles.contains("WorkerABuilder.java")); + assertTrue(generatedFiles.contains("WorkerBBuilder.java")); + assertTrue(generatedFiles.contains("Controller.java")); + assertTrue(generatedFiles.contains("WorkerA.java")); + assertTrue(generatedFiles.contains("WorkerB.java")); + + String controllerBuilderContent = readFileContent(outputPath, "ControllerBuilder.java"); + String workerABuilderContent = readFileContent(outputPath, "WorkerABuilder.java"); + String workerBBuilderContent = readFileContent(outputPath, "WorkerBBuilder.java"); + + assertTrue(controllerBuilderContent.contains("public class ControllerBuilder")); + assertTrue(controllerBuilderContent.contains("public Controller build()")); + assertTrue(controllerBuilderContent.contains("return this;") || controllerBuilderContent.contains("return this ;")); + assertTrue(controllerBuilderContent.contains("String idField") || controllerBuilderContent.contains("String idfield")); + assertTrue(controllerBuilderContent.contains("String statusField") || controllerBuilderContent.contains("String statusfield")); + + assertTrue(workerABuilderContent.contains("public class WorkerABuilder")); + assertTrue(workerABuilderContent.contains("public WorkerA build()")); + assertTrue(workerABuilderContent.contains("String nameField") || workerABuilderContent.contains("String namefield")); + + assertTrue(workerBBuilderContent.contains("public class WorkerBBuilder")); + assertTrue(workerBBuilderContent.contains("public WorkerB build()")); + assertTrue(workerBBuilderContent.contains("String nameField") || workerBBuilderContent.contains("String namefield")); + + String workerAContent = readFileContent(outputPath, "WorkerA.java"); + String workerBContent = readFileContent(outputPath, "WorkerB.java"); + + assertTrue(workerAContent.contains("public void update(") || workerAContent.contains("void update(")); + assertTrue(workerBContent.contains("public void update(") || workerBContent.contains("void update(")); + } +} + diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/ControllerWorkerAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/ControllerWorkerAdapterTest.java new file mode 100644 index 00000000..4fa65245 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/ControllerWorkerAdapterTest.java @@ -0,0 +1,93 @@ +package de.monticore.codeAdaption; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static org.junit.jupiter.api.Assertions.*; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.AdapterParam; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class ControllerWorkerAdapterTest extends AdapterAbstractTest { + private final String resourcesPath = + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/"; + private final File refCD = new File(resourcesPath + "Reference.cd"); + private final File concreteCD = new File(resourcesPath + "Concrete.cd"); + private final Path refCodePath = Path.of(resourcesPath + "concrete"); + private final Path adapterCodePath = Path.of(resourcesPath + "adapter"); + private final Path outputPath = Path.of("target/adapter/controller_worker_observer"); + + private Set confParameters; + private Set adapterParams; + + @BeforeEach + public void setup() { + initMills(); + confParameters = Set.of(NAME_MAPPING, INHERITANCE, STEREOTYPE_MAPPING, STRICT_PARAMETER_ORDER); + adapterParams = Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + } + + @Test + @DisplayName("Builder + Observer Patterns: Adapt Controller and Workers") + public void testControllerWorkerAdaptation() { + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow(() -> { + adapter.adapt(refCD, concreteCD, Set.of("buildPat", "observer"), adapterCodePath, refCodePath, outputPath); + }); + + Set generatedFiles = generatedFileNames(outputPath); + assertTrue(generatedFiles.contains("ControllerBuilder.java")); + assertTrue(generatedFiles.contains("WorkerABuilder.java")); + assertTrue(generatedFiles.contains("WorkerBBuilder.java")); + assertTrue(generatedFiles.contains("Controller.java")); + assertTrue(generatedFiles.contains("WorkerA.java")); + assertTrue(generatedFiles.contains("WorkerB.java")); + + String controllerBuilderContent = readFileContent(outputPath, "ControllerBuilder.java"); + String workerABuilderContent = readFileContent(outputPath, "WorkerABuilder.java"); + String workerBBuilderContent = readFileContent(outputPath, "WorkerBBuilder.java"); + String controllerContent = readFileContent(outputPath, "Controller.java"); + + assertTrue(controllerBuilderContent.contains("public class ControllerBuilder")); + assertTrue(controllerBuilderContent.contains("public Controller build()")); + assertTrue(controllerBuilderContent.contains("return this;") || controllerBuilderContent.contains("return this ;")); + assertTrue(controllerBuilderContent.contains("String idField") || controllerBuilderContent.contains("String idfield")); + assertTrue(controllerBuilderContent.contains("String statusField") || controllerBuilderContent.contains("String statusfield")); + + assertTrue(workerABuilderContent.contains("public class WorkerABuilder")); + assertTrue(workerABuilderContent.contains("public WorkerA build()")); + assertTrue(workerABuilderContent.contains("String nameField") || workerABuilderContent.contains("String namefield")); + + assertTrue(workerBBuilderContent.contains("public class WorkerBBuilder")); + assertTrue(workerBBuilderContent.contains("public WorkerB build()")); + assertTrue(workerBBuilderContent.contains("String nameField") || workerBBuilderContent.contains("String namefield")); + + assertTrue(controllerContent.contains("private String id")); + assertTrue(controllerContent.contains("private String status")); + assertTrue(controllerContent.contains("public Controller(String id, String status)")); + assertTrue(controllerContent.contains("String getId()")); + assertTrue(controllerContent.contains("String getStatus()")); + assertTrue(controllerContent.contains("List observers")); + assertTrue(controllerContent.contains("boolean subscribe(WorkerInterface")); + assertTrue(controllerContent.contains("boolean unsubscribe(WorkerInterface")); + assertTrue(controllerContent.contains("void notifyAll()")); + assertFalse(Files.exists(outputPath.resolve("OSubject.java"))); + assertFalse(Files.exists(outputPath.resolve("OObserver.java"))); + assertFalse(Files.exists(outputPath.resolve("BuilderBuilder.java"))); + + String workerAContent = readFileContent(outputPath, "WorkerA.java"); + String workerBContent = readFileContent(outputPath, "WorkerB.java"); + + assertTrue(workerAContent.contains("public void update(") || workerAContent.contains("void update(")); + assertTrue(workerBContent.contains("public void update(") || workerBContent.contains("void update(")); + } +} + diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/SingletonAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/SingletonAdapterTest.java new file mode 100644 index 00000000..99224e90 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/SingletonAdapterTest.java @@ -0,0 +1,64 @@ +package de.monticore.codeAdaption; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.AdapterParam; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.file.Path; +import java.util.Set; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static org.junit.jupiter.api.Assertions.*; + +public class SingletonAdapterTest extends AdapterAbstractTest { + private final String resourcesPath = + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/"; + private final File refCD = new File(resourcesPath + "Reference.cd"); + private final File concreteCD = new File(resourcesPath + "Concrete.cd"); + private final Path refCodePath = Path.of(resourcesPath + "concrete"); + private final Path adapterCodePath = Path.of(resourcesPath + "adapter"); + private final Path outputPath = Path.of("target/adapter/singleton_pattern"); + + private Set confParameters; + private Set adapterParams; + + @BeforeEach + public void setup() { + initMills(); + confParameters = Set.of(NAME_MAPPING, INHERITANCE, STEREOTYPE_MAPPING, STRICT_PARAMETER_ORDER); + adapterParams = Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + } + + @Test + @DisplayName("Singleton Pattern") + public void testSingletonAdaptation() { + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow( + () -> + adapter.adapt( + refCD, + concreteCD, + Set.of("singleton"), + adapterCodePath, + refCodePath, + outputPath)); + assertFalse(generatedJavaFilesRecursively(outputPath).isEmpty()); + assertNoAdapterMetadata(outputPath); + assertGeneratedJavaCompiles(generatedJavaFilesRecursively(outputPath)); + + String databaseConnection = readFileContent(outputPath, "DatabaseConnection.java"); + String logger = readFileContent(outputPath, "Logger.java"); + assertTrue(databaseConnection.contains("class DatabaseConnection")); + assertTrue(databaseConnection.contains("static DatabaseConnection instance")); + assertTrue(databaseConnection.contains("DatabaseConnection getInstance()")); + assertTrue(logger.contains("class Logger")); + assertTrue(logger.contains("static Logger instance")); + assertTrue(logger.contains("Logger getInstance()")); + } +} + diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/StrategyAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/StrategyAdapterTest.java new file mode 100644 index 00000000..006587aa --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/StrategyAdapterTest.java @@ -0,0 +1,57 @@ +package de.monticore.codeAdaption; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.AdapterParam; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.file.Path; +import java.util.Set; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static org.junit.jupiter.api.Assertions.*; + +public class StrategyAdapterTest extends AdapterAbstractTest { + private final String resourcesPath = + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/"; + private final File refCD = new File(resourcesPath + "Reference.cd"); + private final File concreteCD = new File(resourcesPath + "Concrete.cd"); + private final Path refCodePath = Path.of(resourcesPath + "concrete"); + private final Path adapterCodePath = Path.of(resourcesPath + "adapter"); + private final Path outputPath = Path.of("target/adapter/strategy_pattern"); + + private Set confParameters; + private Set adapterParams; + + @BeforeEach + public void setup() { + initMills(); + confParameters = Set.of(NAME_MAPPING, INHERITANCE, STEREOTYPE_MAPPING, STRICT_PARAMETER_ORDER); + adapterParams = Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + } + + @Test + @DisplayName("Strategy Pattern") + public void testStrategyAdaptation() { + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow( + () -> + adapter.adapt( + refCD, concreteCD, Set.of("strategy"), adapterCodePath, refCodePath, outputPath)); + assertFalse(generatedJavaFilesRecursively(outputPath).isEmpty()); + assertNoAdapterMetadata(outputPath); + assertGeneratedJavaCompiles(generatedJavaFilesRecursively(outputPath)); + + String strategy = readFileContent(outputPath, "PaymentStrategy.java"); + String processor = readFileContent(outputPath, "PaymentProcessor.java"); + assertTrue(strategy.contains("interface PaymentStrategy")); + assertTrue(strategy.contains("void pay(double amount)")); + assertTrue(processor.contains("class PaymentProcessor")); + assertTrue(processor.contains("void processPayment(double amount)")); + } +} + diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/StrategySingletonAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/StrategySingletonAdapterTest.java new file mode 100644 index 00000000..ffa98bcf --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/StrategySingletonAdapterTest.java @@ -0,0 +1,55 @@ +package de.monticore.codeAdaption; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.AdapterParam; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.file.Path; +import java.util.Set; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static org.junit.jupiter.api.Assertions.*; + +public class StrategySingletonAdapterTest extends AdapterAbstractTest { + private final String resourcesPath = + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/"; + private final File refCD = new File(resourcesPath + "Reference.cd"); + private final File concreteCD = new File(resourcesPath + "Concrete.cd"); + private final Path refCodePath = Path.of(resourcesPath + "concrete"); + private final Path adapterCodePath = Path.of(resourcesPath + "adapter"); + private final Path outputPath = Path.of("target/adapter/strategy_singleton_patterns"); + + private Set confParameters; + private Set adapterParams; + + @BeforeEach + public void setup() { + initMills(); + confParameters = Set.of(NAME_MAPPING, INHERITANCE, STEREOTYPE_MAPPING, STRICT_PARAMETER_ORDER, ALLOW_ADDITIONAL_PARAMETERS); + adapterParams = Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + } + + @Test + @DisplayName("Strategy + Singleton Patterns") + public void testStrategySingletonAdaptation() { + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow( + () -> + adapter.adapt( + refCD, + concreteCD, + Set.of("strategy", "singleton"), + adapterCodePath, + refCodePath, + outputPath)); + assertFalse(generatedJavaFilesRecursively(outputPath).isEmpty()); + assertNoAdapterMetadata(outputPath); + assertGeneratedJavaCompiles(generatedJavaFilesRecursively(outputPath)); + } +} + diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/TemplateMethodAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/TemplateMethodAdapterTest.java new file mode 100644 index 00000000..df90bd61 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/TemplateMethodAdapterTest.java @@ -0,0 +1,61 @@ +package de.monticore.codeAdaption; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.AdapterParam; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.file.Path; +import java.util.Set; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static org.junit.jupiter.api.Assertions.*; + +public class TemplateMethodAdapterTest extends AdapterAbstractTest { + private final String resourcesPath = + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/"; + private final File refCD = new File(resourcesPath + "Reference.cd"); + private final File concreteCD = new File(resourcesPath + "Concrete.cd"); + private final Path refCodePath = Path.of(resourcesPath + "concrete"); + private final Path adapterCodePath = Path.of(resourcesPath + "adapter"); + private final Path outputPath = Path.of("target/adapter/template_pattern"); + + private Set confParameters; + private Set adapterParams; + + @BeforeEach + public void setup() { + initMills(); + confParameters = Set.of(NAME_MAPPING, INHERITANCE, STEREOTYPE_MAPPING, STRICT_PARAMETER_ORDER); + adapterParams = Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + } + + @Test + @DisplayName("Template Pattern") + public void testTemplateMethodAdaptation() { + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow(() -> { + adapter.adapt(refCD, concreteCD, Set.of("template"), adapterCodePath, refCodePath, outputPath); + }); + + String dataProcessor = readFileContent(outputPath, "DataProcessor.java"); + assertTrue(dataProcessor.contains("private String source")); + assertTrue(dataProcessor.contains("private String destination")); + assertTrue(dataProcessor.contains("public DataProcessor(String source, String destination)")); + assertTrue(dataProcessor.contains("public abstract void readData()")); + assertTrue(dataProcessor.contains("public abstract void transformData()")); + assertTrue(dataProcessor.contains("public void validateData()")); + assertTrue(dataProcessor.contains("public void templateMethod()")); + assertTrue(dataProcessor.contains("readData();")); + assertTrue(dataProcessor.contains("transformData();")); + assertTrue(dataProcessor.contains("validateData();")); + assertFalse(dataProcessor.contains("primitiveOperation1")); + assertFalse(dataProcessor.contains("primitiveOperation2")); + assertFalse(dataProcessor.contains("void hook()")); + } +} + diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/TemplateObserverAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/TemplateObserverAdapterTest.java new file mode 100644 index 00000000..118f5a27 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/TemplateObserverAdapterTest.java @@ -0,0 +1,69 @@ +package de.monticore.codeAdaption; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.AdapterParam; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.file.Path; +import java.util.Set; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static org.junit.jupiter.api.Assertions.*; + +public class TemplateObserverAdapterTest extends AdapterAbstractTest { + private final String resourcesPath = + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/"; + private final File refCD = new File(resourcesPath + "Reference.cd"); + private final File concreteCD = new File(resourcesPath + "Concrete.cd"); + private final Path refCodePath = Path.of(resourcesPath + "concrete"); + private final Path adapterCodePath = Path.of(resourcesPath + "adapter"); + private final Path outputPath = Path.of("target/adapter/template_observer_patterns"); + + private Set confParameters; + private Set adapterParams; + + @BeforeEach + public void setup() { + initMills(); + confParameters = Set.of(NAME_MAPPING, INHERITANCE, STEREOTYPE_MAPPING, STRICT_PARAMETER_ORDER, ALLOW_ADDITIONAL_PARAMETERS); + adapterParams = Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + } + + @Test + @DisplayName("Template + Observer Pattern") + public void testTemplateObserverAdaptation() { + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow(() -> { + adapter.adapt(refCD, concreteCD, Set.of("template", "observer"), adapterCodePath, refCodePath, outputPath); + }); + + String dataPipeline = readFileContent(outputPath, "DataPipeline.java"); + String pipelineObserver = readFileContent(outputPath, "PipelineObserver.java"); + String loggingObserver = readFileContent(outputPath, "LoggingObserver.java"); + String metricsObserver = readFileContent(outputPath, "MetricsObserver.java"); + + assertTrue(dataPipeline.contains("List observers")); + assertFalse(dataPipeline.contains("List observers")); + assertFalse(dataPipeline.contains("List observers")); + assertEquals(1, count(dataPipeline, "boolean subscribe(PipelineObserver")); + assertEquals(1, count(dataPipeline, "boolean unsubscribe(PipelineObserver")); + assertTrue(dataPipeline.contains("observer.onPipelineStage(null);")); + assertFalse(dataPipeline.contains("observer.update();")); + assertFalse(dataPipeline.contains("primitiveOperation1")); + assertFalse(dataPipeline.contains("primitiveOperation2")); + + assertFalse(pipelineObserver.contains("void update(")); + assertFalse(loggingObserver.contains("void update(")); + assertFalse(metricsObserver.contains("void update(")); + } + + private int count(String content, String needle) { + return content.split(java.util.regex.Pattern.quote(needle), -1).length - 1; + } +} + diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/context/ConcretizationServiceTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/context/ConcretizationServiceTest.java new file mode 100644 index 00000000..444d8818 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/context/ConcretizationServiceTest.java @@ -0,0 +1,163 @@ +package de.monticore.codeAdaption.context; + +import static de.monticore.cdconformance.CDConfParameter.ADAPTED_NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.ALLOW_ADDITIONAL_PARAMETERS; +import static de.monticore.cdconformance.CDConfParameter.ALLOW_CARD_RESTRICTION; +import static de.monticore.cdconformance.CDConfParameter.INHERITANCE; +import static de.monticore.cdconformance.CDConfParameter.METHOD_OVERLOADING; +import static de.monticore.cdconformance.CDConfParameter.NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.SRC_TARGET_ASSOC_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STEREOTYPE_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STRICT_PARAMETER_ORDER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import java.nio.file.Path; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.stream.Collectors; +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; + +class ConcretizationServiceTest extends AdapterAbstractTest { + + private static final Path ROOT = + Path.of("src/test/resources/de/monticore/codeAdaption/cdconcretization"); + + private Set parameters; + + @BeforeEach + void setUp() { + initMills(); + parameters = + Set.of( + STEREOTYPE_MAPPING, + NAME_MAPPING, + SRC_TARGET_ASSOC_MAPPING, + INHERITANCE, + ALLOW_CARD_RESTRICTION, + METHOD_OVERLOADING, + ADAPTED_NAME_MAPPING, + ALLOW_ADDITIONAL_PARAMETERS); + } + + @Test + void completedInheritanceIsVisibleInTheRebuiltIndex() { + ASTCDCompilationUnit completed = + complete( + "inheritance/AttributeInheritanceRef.cd", + "inheritance/AttributeInheritanceConc.cd"); + CDModelIndex index = CDModelIndex.of(completed); + + assertTrue(index.hasType("Person")); + assertEquals(Set.of("Person"), index.directParentNames("Teacher")); + } + + @Test + void upstreamCompletionDoesNotSynthesizeReverseForEachFields() { + ASTCDCompilationUnit completed = + complete( + "evaluation/staticDelegator/attrWorkaround/StaticDelegatorRef.cd", + "evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsConc.cd"); + CDModelIndex index = CDModelIndex.of(completed); + + assertTrue(index.attribute("MyLanguageMill", "foo").isEmpty()); + assertTrue(index.attribute("MyLanguageMill", "_foo").isPresent()); + } + + @Test + void completedEnumConstantIsVisibleInTheRebuiltIndex() { + ASTCDCompilationUnit completed = + complete("types/enums/EnumMemberMissingRef.cd", "types/enums/EnumMemberMissingConc.cd"); + CDModelIndex index = CDModelIndex.of(completed); + + assertEquals( + Set.of("RED", "GREEN", "YELLOW", "BLUE", "PURPLE"), + index.enums().get(0).getCDEnumConstantList().stream() + .map(constant -> constant.getName()) + .collect(java.util.stream.Collectors.toSet())); + } + + @Test + void completedInterfaceIsVisibleInTheRebuiltIndex() { + ASTCDCompilationUnit completed = + complete("types/valid/TypeMissingRef.cd", "types/valid/TypeMissingConc.cd"); + CDModelIndex index = CDModelIndex.of(completed); + + assertTrue(index.directParentNames("Course").contains("Teachable")); + } + + @Test + void upstreamCompletionDoesNotSynthesizeMultiIncarnationAccountAlias() { + ASTCDCompilationUnit completed = + complete( + "evaluation/banking/BankingRef.cd", + "evaluation/banking/multiInc/BankingConc.cd"); + CDModelIndex index = CDModelIndex.of(completed); + + assertTrue(index.attribute("Transaction", "sourceAccount").isEmpty()); + } + + @Test + void upstreamCompletionDoesNotSynthesizeCrossReferenceForEachMethod() { + ASTCDCompilationUnit completed = + complete( + "evaluation/cross-references/MicroserviceRef.cd", + "evaluation/cross-references/MicroserviceConc.cd"); + CDModelIndex index = CDModelIndex.of(completed); + + assertTrue(index.methods("UserService", "sendToOrderService").isEmpty()); + } + + @ParameterizedTest(name = "allow additional parameters = {0}") + @ValueSource(booleans = {false, true}) + void visitorCompletionProducesAllOverloads(boolean allowAdditionalParameters) { + Set completionParameters = new LinkedHashSet<>(parameters); + if (!allowAdditionalParameters) { + completionParameters.remove(ALLOW_ADDITIONAL_PARAMETERS); + } + completionParameters.add(STRICT_PARAMETER_ORDER); + + assertVisitorCompletion(completionParameters); + } + + private void assertVisitorCompletion(Set completionParameters) { + ASTCDCompilationUnit referenceCD = + JavaLoader.parseCD(ROOT.resolve("evaluation/visitor/VisitorRef.cd").toString()); + ASTCDCompilationUnit concreteCD = + JavaLoader.parseCD(ROOT.resolve("evaluation/visitor/VisitorConc.cd").toString()); + ASTCDCompilationUnit originalConcreteCD = concreteCD.deepClone(); + + ASTCDCompilationUnit completed = + new ConcretizationService(completionParameters) + .completeConcreteCD(concreteCD, referenceCD, Set.of("ref")); + CDModelIndex completedIndex = CDModelIndex.of(completed); + + assertEquals( + Set.of("visit(Node)", "visit(RootNode)", "visit(InnerNode)", "visit(LeafNode)"), + completedIndex.methods("NodeVisitor", "visit").stream() + .map(JavaSourceNames::methodSignature) + .collect(Collectors.toSet())); + assertTrue( + concreteCD.deepEquals(originalConcreteCD, false), + "Concretization must leave the caller-owned concrete AST unchanged"); + assertTrue( + CDModelIndex.of(concreteCD).methods("NodeVisitor").isEmpty(), + "Completed Visitor declarations must exist only in the returned clone"); + } + + private ASTCDCompilationUnit complete(String reference, String concrete) { + ASTCDCompilationUnit referenceCD = JavaLoader.parseCD(ROOT.resolve(reference).toString()); + ASTCDCompilationUnit concreteCD = JavaLoader.parseCD(ROOT.resolve(concrete).toString()); + return new ConcretizationService(parameters) + .completeConcreteCD(concreteCD, referenceCD, Set.of("ref")); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/context/GroupingMappingServiceTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/context/GroupingMappingServiceTest.java new file mode 100644 index 00000000..4d508ad4 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/context/GroupingMappingServiceTest.java @@ -0,0 +1,50 @@ +package de.monticore.codeAdaption.context; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.utils.JavaLoader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class GroupingMappingServiceTest { + @TempDir Path temporaryDirectory; + + @BeforeEach + void initializeMills() { + AdapterAbstractTest.initMills(); + } + + @Test + void mapsConcreteSimpleNamesToGroupingSimpleNamesAndOmitsIdentityMappings() + throws IOException { + Path modelFile = temporaryDirectory.resolve("Model.cd"); + Files.writeString( + modelFile, "classdiagram Model { class Concrete; class Group; class Identity; }"); + ASTCDCompilationUnit model = JavaLoader.parseCD(modelFile.toString()); + var types = model.getCDDefinition().getCDClassesList(); + var group = types.stream().filter(type -> "Group".equals(type.getName())).findFirst().orElseThrow(); + var identity = + types.stream().filter(type -> "Identity".equals(type.getName())).findFirst().orElseThrow(); + IncarnationContext context = + new IncarnationContext( + "mapping", + Map.of(), + Map.of( + StableElementKey.type("Concrete"), + new IncarnationContext.MappedElement(StableElementKey.type("Group"), group.getSymbol()), + StableElementKey.type("Identity"), + new IncarnationContext.MappedElement( + StableElementKey.type("Identity"), identity.getSymbol()))); + + assertEquals(Map.of("Concrete", "Group"), new GroupingMappingService().compute(context)); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/context/MappingConformanceServiceTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/context/MappingConformanceServiceTest.java new file mode 100644 index 00000000..c55962e6 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/context/MappingConformanceServiceTest.java @@ -0,0 +1,73 @@ +package de.monticore.codeAdaption.context; + +import static de.monticore.cdconformance.CDConfParameter.NAME_MAPPING; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class MappingConformanceServiceTest extends AdapterAbstractTest { + + @TempDir Path tempDir; + + @BeforeEach + void setUp() { + initMills(); + LogStub.init(); + } + + @Test + void failedCheckRestoresFailQuickWithoutLeakingErrors() throws IOException { + ASTCDCompilationUnit reference = + parse("Reference.cd", "classdiagram Reference { class Required { int value; } }"); + ASTCDCompilationUnit concrete = + parse("Concrete.cd", "classdiagram Concrete { class Unrelated; }"); + MappingConformanceService service = new MappingConformanceService(Set.of(NAME_MAPPING)); + long errorsBefore = Log.getErrorCount(); + Log.enableFailQuick(true); + + boolean valid = + service.checkOrFalse(service.newChecker(), concrete, reference, "ref"); + + assertFalse(valid); + assertTrue(Log.isFailQuickEnabled()); + assertEquals(errorsBefore, Log.getErrorCount()); + } + + @Test + void manualFallbackDoesNotRetainFailedChecker() throws IOException { + ASTCDCompilationUnit reference = + parse("Reference.cd", "classdiagram Reference { class Required { int value; } }"); + ASTCDCompilationUnit concrete = + parse("Concrete.cd", "classdiagram Concrete { class Unrelated; }"); + MappingConformanceService service = new MappingConformanceService(Set.of(NAME_MAPPING)); + + AdaptationContextFactory.AdaptationContextResult result = + new AdaptationContextFactory(Set.of(NAME_MAPPING), service) + .buildResults( + CDModelIndex.of(reference), CDModelIndex.of(concrete), Set.of("ref"), true) + .get("ref"); + + assertFalse(result.conformanceValid()); + assertEquals(null, result.checker()); + } + + private ASTCDCompilationUnit parse(String name, String source) throws IOException { + Path path = tempDir.resolve(name); + Files.writeString(path, source); + return JavaLoader.parseCD(path.toString()); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/AssociationPatternAdaptationTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/AssociationPatternAdaptationTest.java new file mode 100644 index 00000000..fb91a2fd --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/AssociationPatternAdaptationTest.java @@ -0,0 +1,128 @@ +package de.monticore.codeAdaption.evaluation; + +import static de.monticore.cdconformance.CDConfParameter.ADAPTED_NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.INHERITANCE; +import static de.monticore.cdconformance.CDConfParameter.NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.SRC_TARGET_ASSOC_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STEREOTYPE_MAPPING; +import static de.monticore.codeAdaption.utils.AdapterParam.ANNOTATION_MATCHING; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_TYPE; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_VAR; +import static de.monticore.codeAdaption.utils.AdapterParam.NAME_MATCHING; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.codeAdaption.CodeAdapter; +import de.monticore.codeAdaption.testutil.CD4CodeTestGenerator; +import java.io.File; +import java.nio.file.Path; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class AssociationPatternAdaptationTest extends EvaluationAbstractTest { + + @BeforeEach + void setup() { + initMills(); + configureFixture("association_role_usage_mi"); + adapterParams = + Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + confParameters = + Set.of( + STEREOTYPE_MAPPING, + NAME_MAPPING, + ADAPTED_NAME_MAPPING, + SRC_TARGET_ASSOC_MAPPING, + INHERITANCE); + } + + @Test + void adaptsMultiIncarnationAssociationRoleUsage() { + deleteRecursively(output); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow( + () -> + adapter.adapt( + referenceCD, + concreteCD, + Set.of("ref"), + refCodePath, + conCodePath, + output, + true, + true)); + + String adaptedTeacher = readFileContent(output, "Teacher.java"); + assertTrue(adaptedTeacher.contains("firstMathDept(MathDept fallback)")); + assertTrue(adaptedTeacher.contains("firstScienceDept(ScienceDept fallback)")); + assertTrue(adaptedTeacher.contains("for (MathDept department : this.mathDepts)")); + assertTrue( + adaptedTeacher.contains( + "for (ScienceDept department : this.scienceDepts)")); + assertFalse(adaptedTeacher.contains("this.departments)")); + + Path generated = output.resolve("generated"); + assertDoesNotThrow(() -> CD4CodeTestGenerator.generate(concreteCD, output, generated)); + + String generatedTeacherTop = readFileContent(generated, "TeacherTOP.java"); + assertTrue( + generatedTeacherTop.contains("java.util.Set mathDepts")); + assertTrue( + generatedTeacherTop.contains( + "java.util.Set scienceDepts")); + + assertNoAdapterMetadata(output); + assertGeneratedJavaCompiles(output); + } + + @Test + void adaptsBidirectionalAssociationRoleWritesOnBothOwners() { + configureFixture("association_bidirectional_role_write"); + deleteRecursively(output); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + assertDoesNotThrow( + () -> + adapter.adapt( + referenceCD, + concreteCD, + Set.of("ref"), + refCodePath, + conCodePath, + output, + true, + true)); + + String adaptedSprint = readFileContent(output, "Sprint.java"); + assertTrue(adaptedSprint.contains("replaceTicket(Ticket replacement)")); + assertTrue(adaptedSprint.contains("this.tickets = replacement")); + assertFalse(adaptedSprint.contains("this.tasks")); + + String adaptedTicket = readFileContent(output, "Ticket.java"); + assertTrue(adaptedTicket.contains("moveToSprint(Sprint replacement)")); + assertTrue(adaptedTicket.contains("this.sprint = replacement")); + assertFalse(adaptedTicket.contains("this.project")); + + Path generated = output.resolve("generated"); + assertDoesNotThrow(() -> CD4CodeTestGenerator.generate(concreteCD, output, generated)); + + String generatedSprintTop = readFileContent(generated, "SprintTOP.java"); + assertTrue(generatedSprintTop.contains("Concrete.Ticket tickets")); + String generatedTicketTop = readFileContent(generated, "TicketTOP.java"); + assertTrue(generatedTicketTop.contains("Concrete.Sprint sprint")); + + assertNoAdapterMetadata(output); + assertGeneratedJavaCompiles(output); + } + + private void configureFixture(String fixture) { + referenceCD = new File(resourcesPath + fixture + "/Reference.cd"); + concreteCD = new File(resourcesPath + fixture + "/Concrete.cd"); + refCodePath = Path.of(resourcesPath + fixture + "/adapter"); + conCodePath = Path.of(resourcesPath + fixture + "/concrete"); + output = Path.of("target/codeAdapter/evaluation/" + fixture); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase1.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase1.java index caf2445f..c589b0bd 100644 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase1.java +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase1.java @@ -2,8 +2,10 @@ import static de.monticore.cdconformance.CDConfParameter.*; import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -import de.monticore.cd4code.CD4CodeMill; import de.monticore.codeAdaption.CodeAdapter; import java.io.File; import java.nio.file.Path; @@ -21,7 +23,8 @@ public void setup() { refCodePath = Path.of(resourcesPath + "testcase_1/reference"); conCodePath = Path.of(resourcesPath + "testcase_1/concrete"); output = Path.of("target/codeAdapter/evaluation/testcase_1/"); - CD4CodeMill.init(); + initMills(); + deleteRecursively(output); adapterParams = Set.of(NAME_MATCHING, ANNOTATION_MATCHING, INFIX_MATCHING, IGNORE_NON_MATCHED_VAR); confParameters = Set.of(INHERITANCE, STEREOTYPE_MAPPING, SRC_TARGET_ASSOC_MAPPING); @@ -32,6 +35,18 @@ public void setup() { public void evaluationCodeAdapterCaseStudy1Test() { Set mappings = Set.of("stud", "prof"); CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); - adapter.adapt(referenceCD, concreteCD, mappings, refCodePath, conCodePath, output); + assertDoesNotThrow( + () -> adapter.adapt(referenceCD, concreteCD, mappings, refCodePath, conCodePath, output)); + assertFalse(generatedJavaFilesRecursively(output).isEmpty()); + assertNoAdapterMetadata(output); + assertTrue(generatedFileNames(output).contains("ProfessorRegistration.java")); + assertTrue(generatedFileNames(output).contains("StudentRegistration.java")); + assertTrue( + readFileContent(output, "ProfessorRegistration.java") + .contains("register(Professor professor)")); + assertTrue( + readFileContent(output, "StudentRegistration.java") + .contains("register(Student student)")); + assertGeneratedJavaCompiles(output); } } diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase2a.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase2a.java index a752ad75..071383b7 100644 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase2a.java +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase2a.java @@ -2,11 +2,13 @@ import static de.monticore.cdconformance.CDConfParameter.*; import static de.monticore.codeAdaption.utils.AdapterParam.*; -import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_VAR; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import de.monticore.cd4code.CD4CodeMill; import de.monticore.codeAdaption.CodeAdapter; -import de.monticore.codeAdaption.utils.Generator; +import de.monticore.codeAdaption.testutil.CD4CodeTestGenerator; import java.io.File; import java.nio.file.Path; import java.util.Set; @@ -31,12 +33,32 @@ public void setup() { @Test @DisplayName("Evaluation Code Adapter Case Study 2 CD4Code") - public void evaluationCodeAdapterCaseStudy1Test() { + public void adaptsAssociationRoleUsageAndGeneratesRoleField() { Set mappings = Set.of("stud"); CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); - adapter.adapt(referenceCD, concreteCD, mappings, refCodePath, conCodePath, output); + deleteRecursively(output); + + assertDoesNotThrow( + () -> adapter.adapt(referenceCD, concreteCD, mappings, refCodePath, conCodePath, output)); + + String adaptedStudent = readFileContent(output, "Student.java"); + assertTrue(adaptedStudent.contains("package Concrete;")); + assertTrue(adaptedStudent.contains("class Student extends StudentTOP")); + assertTrue(adaptedStudent.contains("printHiwiRoles()")); + assertTrue(adaptedStudent.contains("for (HiwiRole hiwiRole : this.roles)")); + assertTrue(adaptedStudent.contains("roleNames = hiwiRole.name")); + assertFalse(adaptedStudent.contains("Role role")); + assertFalse(adaptedStudent.contains("printRoles()")); Path genCode = Path.of("target/codeAdapter/evaluation/testcase_2_cd4code/generated"); - Generator.generate(concreteCD, output, genCode); + assertDoesNotThrow(() -> CD4CodeTestGenerator.generate(concreteCD, output, genCode)); + + String generatedStudentTop = readFileContent(genCode, "StudentTOP.java"); + assertTrue(generatedStudentTop.contains("abstract class StudentTOP")); + assertTrue(generatedStudentTop.contains("java.util.Set roles")); + assertFalse(generatedStudentTop.contains("Set")); + + assertNoAdapterMetadata(output); + assertGeneratedJavaCompiles(output); } } diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CombinedPatternEvaluationTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CombinedPatternEvaluationTest.java new file mode 100644 index 00000000..da6d2216 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CombinedPatternEvaluationTest.java @@ -0,0 +1,159 @@ +package de.monticore.codeAdaption.evaluation; + +import static de.monticore.cdconformance.CDConfParameter.ALLOW_ADDITIONAL_PARAMETERS; +import static de.monticore.cdconformance.CDConfParameter.INHERITANCE; +import static de.monticore.cdconformance.CDConfParameter.NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STEREOTYPE_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STRICT_PARAMETER_ORDER; +import static de.monticore.codeAdaption.utils.AdapterParam.ANNOTATION_MATCHING; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_TYPE; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_VAR; +import static de.monticore.codeAdaption.utils.AdapterParam.NAME_MATCHING; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.codeAdaption.CodeAdapter; +import java.io.File; +import java.nio.file.Path; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** Executable evaluation wrappers for combined-pattern resource cases. */ +public class CombinedPatternEvaluationTest extends EvaluationAbstractTest { + + @BeforeEach + public void setup() { + initMills(); + adapterParams = + Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE); + confParameters = + Set.of( + NAME_MAPPING, + INHERITANCE, + STEREOTYPE_MAPPING, + STRICT_PARAMETER_ORDER, + ALLOW_ADDITIONAL_PARAMETERS); + } + + @Test + @DisplayName("Evaluation Code Adapter Case Study 14 Adapter + Factory") + public void adapterFactoryCombinedCaseRuns() { + runCombinedCase("testcase_14_adapter_factory_combined", Set.of("adapter", "factory")); + assertEquals( + Set.of("CarrierAdapter.java", "LegacyCarrier.java", "ShippingFactory.java", "ShippingPort.java"), + generatedFileNames(output)); + assertNoAdapterMetadata(output); + assertGeneratedJavaCompiles(output); + + String carrierAdapter = readFileContent(output, "CarrierAdapter.java"); + String shippingFactory = readFileContent(output, "ShippingFactory.java"); + String shippingPort = readFileContent(output, "ShippingPort.java"); + + assertTrue(carrierAdapter.contains("public class CarrierAdapter implements ShippingPort")); + assertTrue(carrierAdapter.contains("public CarrierAdapter(LegacyCarrier carrier)")); + assertTrue(carrierAdapter.contains("public boolean ship(String label, boolean insured)")); + assertTrue(carrierAdapter.contains("carrier.dispatch(label, insured)")); + assertTrue(shippingFactory.contains("public ShippingPort createCarrier(LegacyCarrier carrier)")); + assertTrue(shippingFactory.contains("return new CarrierAdapter(carrier);")); + assertTrue(shippingPort.contains("boolean ship(String label, boolean insured);")); + assertFalse(carrierAdapter.contains("specificRequest")); + assertFalse(carrierAdapter.contains("boolean request(")); + } + + @Test + @DisplayName("Evaluation Code Adapter Case Study 15 Composite + Decorator") + public void compositeDecoratorCombinedCaseRuns() { + runCombinedCase("testcase_15_composite_decorator_combined", Set.of("composite", "decorator")); + assertEquals( + Set.of( + "BorderDecorator.java", + "GroupNode.java", + "ImageNode.java", + "Renderable.java", + "RenderDecorator.java", + "ShadowDecorator.java", + "TextNode.java"), + generatedFileNames(output)); + assertNoAdapterMetadata(output); + assertGeneratedJavaCompiles(output); + + String renderable = readFileContent(output, "Renderable.java"); + String groupNode = readFileContent(output, "GroupNode.java"); + String renderDecorator = readFileContent(output, "RenderDecorator.java"); + String borderDecorator = readFileContent(output, "BorderDecorator.java"); + String shadowDecorator = readFileContent(output, "ShadowDecorator.java"); + + assertTrue(renderable.contains("public interface Renderable")); + assertTrue(renderable.contains("String render(int depth);")); + assertTrue(groupNode.contains("public class GroupNode implements Renderable")); + assertTrue(groupNode.contains("List nodes")); + assertTrue(groupNode.contains("public void attach(Renderable node)")); + assertTrue(groupNode.contains("public void detach(Renderable node)")); + assertTrue(groupNode.contains("node.render(depth + 1)")); + assertTrue(renderDecorator.contains("public abstract class RenderDecorator implements Renderable")); + assertTrue(renderDecorator.contains("Renderable wrapped")); + assertTrue(renderDecorator.contains("return wrapped.render(depth);")); + assertTrue(borderDecorator.contains("public class BorderDecorator extends RenderDecorator")); + assertTrue(shadowDecorator.contains("public class ShadowDecorator extends RenderDecorator")); + assertFalse(borderDecorator.contains("abstract class BorderDecorator")); + assertFalse(shadowDecorator.contains("abstract class ShadowDecorator")); + assertFalse(groupNode.contains("Component")); + assertFalse(groupNode.contains("operation(")); + } + + @Test + @DisplayName("Evaluation Code Adapter Case Study 16 Observer + Command") + public void observerCommandCombinedCaseRuns() { + runCombinedCase("testcase_16_observer_command_combined", Set.of("observer", "command")); + assertEquals( + Set.of( + "CommandQueue.java", + "EmailCommand.java", + "EventBus.java", + "SmsCommand.java", + "WorkflowCommand.java"), + generatedFileNames(output)); + assertNoAdapterMetadata(output); + assertGeneratedJavaCompiles(output); + + String eventBus = readFileContent(output, "EventBus.java"); + String commandQueue = readFileContent(output, "CommandQueue.java"); + String workflowCommand = readFileContent(output, "WorkflowCommand.java"); + String emailCommand = readFileContent(output, "EmailCommand.java"); + String smsCommand = readFileContent(output, "SmsCommand.java"); + + assertTrue(workflowCommand.contains("public interface WorkflowCommand")); + assertTrue(workflowCommand.contains("void run(String event, boolean async);")); + assertTrue(emailCommand.contains("public class EmailCommand implements WorkflowCommand")); + assertTrue(smsCommand.contains("public class SmsCommand implements WorkflowCommand")); + assertTrue(eventBus.contains("List listeners")); + assertTrue(eventBus.contains("public void subscribe(WorkflowCommand command)")); + assertTrue(eventBus.contains("public void unsubscribe(WorkflowCommand command)")); + assertTrue(eventBus.contains("public void publish(String event)")); + assertTrue(eventBus.contains("listener.run(event, false)")); + assertTrue(commandQueue.contains("List backlog")); + assertTrue(commandQueue.contains("public void schedule(WorkflowCommand command)")); + assertTrue(commandQueue.contains("public void drain(String event)")); + assertTrue(commandQueue.contains("command.run(event, false)")); + assertFalse(eventBus.contains("void update(")); + assertFalse(eventBus.contains("void notifyAll(")); + assertFalse(commandQueue.contains("execute(")); + assertFalse(commandQueue.contains("runAll(")); + } + + private void runCombinedCase(String caseName, Set mappings) { + referenceCD = new File(resourcesPath + caseName + "/Reference.cd"); + concreteCD = new File(resourcesPath + caseName + "/Concrete.cd"); + refCodePath = Path.of(resourcesPath + caseName + "/adapter"); + conCodePath = Path.of(resourcesPath + caseName + "/concrete"); + output = Path.of("target/codeAdapter/evaluation/" + caseName); + + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + assertDoesNotThrow( + () -> adapter.adapt(referenceCD, concreteCD, mappings, refCodePath, conCodePath, output)); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/ConfCheckerEvalTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/ConfCheckerEvalTest.java deleted file mode 100644 index b5a1f290..00000000 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/ConfCheckerEvalTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package de.monticore.codeAdaption.evaluation; - -import static de.monticore.cdconformance.CDConfParameter.*; - -import de.monticore.cd4code.CD4CodeMill; -import de.monticore.cdbasis._ast.ASTCDCompilationUnit; -import de.monticore.cdconformance.CDConformanceChecker; -import de.monticore.codeAdaption.utils.JavaLoader; -import de.se_rwth.commons.logging.Log; -import java.io.File; -import java.nio.file.Path; -import java.util.Set; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -public class ConfCheckerEvalTest extends EvaluationAbstractTest { - @BeforeEach - public void setup() { - referenceCD = new File(resourcesPath + "confCheckingCD/Reference.cd"); - concreteCD = new File(resourcesPath + "confCheckingCD/Concrete.cd"); - refCodePath = Path.of(resourcesPath + "confCheckingCD/reference"); - conCodePath = Path.of(resourcesPath + "confCheckingCD/concrete"); - output = Path.of("target/codeAdapter/evaluation/confCheckingCD/"); - CD4CodeMill.init(); - Log.init(); - confParameters = Set.of(INHERITANCE, STEREOTYPE_MAPPING, SRC_TARGET_ASSOC_MAPPING); - } - - @Test - @DisplayName("Evaluation conformance checker for class diagrams") - public void evaluationConformanceCheckerCDtest() { - long start = System.currentTimeMillis(); - Set mappings = Set.of("prof", "stud"); - ASTCDCompilationUnit conCD = JavaLoader.loadCD(concreteCD); - ASTCDCompilationUnit refCD = JavaLoader.loadCD(referenceCD); - - CDConformanceChecker conformanceChecker = new CDConformanceChecker(confParameters); - Assertions.assertTrue(conformanceChecker.checkConformance(conCD, refCD, mappings)); - double duration = (System.currentTimeMillis() - start) / 1000.0; - System.out.println("duration: " + duration); - } - - @Test - @DisplayName("Evaluation conformance checker design patterns") - public void evaluationConformanceCheckerCDtest2() { - long start = System.currentTimeMillis(); - Set mappings = Set.of("ci", "re"); - ASTCDCompilationUnit conCD = JavaLoader.loadCD( - new File(resourcesPath + "design-patterns/Graphic.cd")); - ASTCDCompilationUnit refCD = JavaLoader.loadCD( - new File(resourcesPath + "design-patterns/Composition.cd")); - - CDConformanceChecker conformanceChecker = new CDConformanceChecker(confParameters); - Assertions.assertTrue(conformanceChecker.checkConformance(conCD, refCD, mappings)); - - mappings = Set.of("npg"); - refCD = JavaLoader.loadCD(new File(resourcesPath + "design-patterns/Adapter.cd")); - Assertions.assertTrue(conformanceChecker.checkConformance(conCD, refCD, mappings)); - - - double duration = (System.currentTimeMillis() - start) / 1000.0; - System.out.println("duration: " + duration); - } -} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/DesignPatternTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/DesignPatternTest.java new file mode 100644 index 00000000..094fde85 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/DesignPatternTest.java @@ -0,0 +1,87 @@ +package de.monticore.codeAdaption.evaluation; + +import static de.monticore.cdconformance.CDConfParameter.INHERITANCE; +import static de.monticore.cdconformance.CDConfParameter.SRC_TARGET_ASSOC_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STEREOTYPE_MAPPING; +import static de.monticore.codeAdaption.utils.AdapterParam.ANNOTATION_MATCHING; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_VAR; +import static de.monticore.codeAdaption.utils.AdapterParam.INFIX_MATCHING; +import static de.monticore.codeAdaption.utils.AdapterParam.NAME_MATCHING; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.codeAdaption.CodeAdapter; +import de.monticore.codeAdaption.testutil.CD4CodeTestGenerator; +import java.io.File; +import java.nio.file.Path; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class DesignPatternTest extends EvaluationAbstractTest { + @BeforeEach + public void setup() { + initMills(); + adapterParams = + Set.of(NAME_MATCHING, ANNOTATION_MATCHING, INFIX_MATCHING, IGNORE_NON_MATCHED_VAR); + confParameters = Set.of(INHERITANCE, STEREOTYPE_MAPPING, SRC_TARGET_ASSOC_MAPPING); + } + + @Test + @DisplayName("Evaluation paper example: Composite pattern") + public void adaptsCompositePatternForBothMappings() { + configureFixture("Composition", "composition"); + + adaptAndGenerate(Set.of("ci", "re")); + + assertTrue( + generatedFileNames(output) + .containsAll(Set.of("Circle.java", "Graphic.java", "Picture.java", "Rectangle.java"))); + String picture = readFileContent(output, "Picture.java"); + assertTrue(picture.contains("class Picture implements Graphic")); + assertTrue(picture.contains("void render()")); + assertTrue(picture.contains("List graphicList")); + assertFalse(picture.contains("Component")); + assertFalse(picture.contains("execute(")); + assertNoAdapterMetadata(output); + assertGeneratedJavaCompiles(output); + } + + @Test + @DisplayName("Evaluation paper example: Adapter pattern") + public void adaptsAdapterPattern() { + configureFixture("Adapter", "adapter"); + + adaptAndGenerate(Set.of("npg")); + + assertTrue( + generatedFileNames(output) + .containsAll(Set.of("FlexImage.java", "NPGAdapter.java", "NPGImage.java"))); + String adapter = readFileContent(output, "NPGAdapter.java"); + assertTrue(adapter.contains("class NPGAdapter implements FlexImage")); + assertTrue(adapter.contains("void flex()")); + assertFalse(adapter.contains("Target")); + assertFalse(adapter.contains("operation(")); + assertNoAdapterMetadata(output); + assertGeneratedJavaCompiles(output); + } + + private void configureFixture(String referenceName, String codeDirectory) { + referenceCD = new File(resourcesPath + "design_patterns/" + referenceName + ".cd"); + concreteCD = new File(resourcesPath + "design_patterns/DesignPatterns.cd"); + refCodePath = Path.of(resourcesPath + "design_patterns/hwc/" + codeDirectory); + conCodePath = Path.of(resourcesPath + "design_patterns/concrete"); + output = Path.of("target/codeAdapter/evaluation/design_patterns/" + codeDirectory); + } + + private void adaptAndGenerate(Set mappings) { + deleteRecursively(output); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + assertDoesNotThrow( + () -> adapter.adapt(referenceCD, concreteCD, mappings, refCodePath, conCodePath, output)); + assertDoesNotThrow( + () -> CD4CodeTestGenerator.generate(concreteCD, output, output.resolve("generated"))); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/BasicUpdateHandlerTestAccess.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/BasicUpdateHandlerTestAccess.java new file mode 100644 index 00000000..c3118776 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/BasicUpdateHandlerTestAccess.java @@ -0,0 +1,36 @@ +package de.monticore.codeAdaption.handler; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.symboltable.ISymbol; +import java.util.Map; +import java.util.Optional; + +/** Test access to package-private handler resolution without a production inheritance hook. */ +public final class BasicUpdateHandlerTestAccess { + + private BasicUpdateHandlerTestAccess() {} + + public static Optional resolve( + IncarnationContext incarnationContext, + ASTCDCompilationUnit reference, + ASTCDCompilationUnit concrete, + Map selection, + boolean useCommonParentForMultipleIncarnations, + ISymbol symbol) { + BasicUpdateHandler handler = + new BasicUpdateHandler( + CDModelIndex.of(reference), + CDModelIndex.of(concrete), + CDModelIndex.of(concrete), + null, + null, + null, + incarnationContext, + selection, + useCommonParentForMultipleIncarnations); + return handler.getSymbolFromContext(symbol); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/JavaTypeUpdateServiceTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/JavaTypeUpdateServiceTest.java new file mode 100644 index 00000000..14c30a2c --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/JavaTypeUpdateServiceTest.java @@ -0,0 +1,85 @@ +package de.monticore.codeAdaption.handler; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.JavaLoader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class JavaTypeUpdateServiceTest { + @TempDir Path temporaryDirectory; + + @BeforeEach + void initializeMills() { + AdapterAbstractTest.initMills(); + } + + @Test + void findsInterfacesIntroducedOnACompletedSuperclass() throws IOException { + CDModelIndex input = + index( + "Input.cd", + "classdiagram Input { class BankAccount; " + + "class SavingsAccount extends BankAccount; }"); + CDModelIndex completed = + index( + "Completed.cd", + "import java.lang.String; classdiagram Completed { " + + "interface Auditable { String generateReport(); } " + + "abstract class BankAccount implements Auditable; " + + "class SavingsAccount extends BankAccount; }"); + + Set inputInterfaces = + JavaTypeUpdateService.effectiveInterfaceNames(input, "SavingsAccount"); + Set completedInterfaces = + JavaTypeUpdateService.effectiveInterfaceNames(completed, "SavingsAccount"); + completedInterfaces.removeAll(inputInterfaces); + + assertEquals(Set.of("Auditable"), completedInterfaces); + } + + @ParameterizedTest(name = "{0} implements {1}: {2}") + @MethodSource("implementationReturnCases") + void checksImplementationReturnCompatibility( + String actualReturn, String requiredReturn, boolean compatible) throws IOException { + CDModelIndex index = + index( + "Returns.cd", + "classdiagram Returns { class Parent; class Child extends Parent; class Other; }"); + + assertEquals( + compatible, + JavaTypeUpdateService.isCompatibleImplementationReturn( + index, actualReturn, requiredReturn)); + } + + private static Stream implementationReturnCases() { + return Stream.of( + Arguments.of("int", "int", true), + Arguments.of("Child", "Parent", true), + Arguments.of("String", "Object", true), + Arguments.of("Child[]", "Object", true), + Arguments.of("Parent", "Child", false), + Arguments.of("Other", "Parent", false), + Arguments.of("int", "long", false), + Arguments.of("void", "Object", false), + Arguments.of("Object", "void", false)); + } + + private CDModelIndex index(String fileName, String source) throws IOException { + Path cd = temporaryDirectory.resolve(fileName); + Files.writeString(cd, source); + return CDModelIndex.of(JavaLoader.parseCD(cd.toString())); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/multiIncarnation/AdaptationConflictDetectorTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/multiIncarnation/AdaptationConflictDetectorTest.java new file mode 100644 index 00000000..2db32686 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/multiIncarnation/AdaptationConflictDetectorTest.java @@ -0,0 +1,245 @@ +package de.monticore.codeAdaption.handler.multiIncarnation; + +import static de.monticore.cdconformance.CDConfParameter.INHERITANCE; +import static de.monticore.cdconformance.CDConfParameter.NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STEREOTYPE_MAPPING; +import static de.monticore.codeAdaption.utils.AdapterParam.ANNOTATION_MATCHING; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_TYPE; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_VAR; +import static de.monticore.codeAdaption.utils.AdapterParam.NAME_MATCHING; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.CodeAdaptationException; +import de.monticore.codeAdaption.CodeAdapter; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.se_rwth.commons.logging.LogStub; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +public class AdaptationConflictDetectorTest extends AdapterAbstractTest { + private static final Path ROOT = + Path.of("src/test/resources/de/monticore/codeAdaption/conflicts"); + private static final Path EVALUATION_ROOT = + Path.of("src/test/resources/de/monticore/codeAdaption/evaluation"); + private static final Set MAPPINGS = Set.of("ref"); + + private Set confParams; + + @BeforeEach + public void setup() { + LogStub.init(); + initMills(); + confParams = Set.of(STEREOTYPE_MAPPING, NAME_MAPPING, INHERITANCE); + } + + @ParameterizedTest(name = "{0} -> {2}") + @CsvSource({ + "AmbiguousOverloadRef.cd, AmbiguousOverloadConc.cd, ambiguous overloaded", + "TypeKindRef.cd, TypeKindConc.cd, type-kind mismatch", + "FieldConflictRef.cd, FieldConflictConc.cd, inherited field conflict", + "MethodConflictRef.cd, MethodConflictConc.cd, duplicate method", + "EnumOrderRef.cd, EnumOrderConc.cd, enum order conflict", + "AssociationCardinalityRef.cd, AssociationCardinalityConc.cd, cardinality", + "AssociationAmbiguousDirectionRef.cd, AssociationAmbiguousDirectionConc.cd, ambiguous association direction", + "AssociationRoleConflictRef.cd, AssociationRoleConflictConc.cd, association role field conflict", + "AnyRef.cd, AnyConc.cd, underspecified attribute type" + }) + void detectsInvalidManualAdaptation( + String reference, String concrete, String expectedMessagePart) { + assertConflict(reference, concrete, expectedMessagePart); + } + + @Test + public void acceptsDeterministicExplicitMappings() { + assertDoesNotThrow(() -> validate("ValidManualRef.cd", "ValidManualConc.cd")); + } + + @Test + public void acceptsEvaluationTestcase1ObserverChainRoles() { + ASTCDCompilationUnit refCD = + JavaLoader.parseCD(EVALUATION_ROOT.resolve("testcase_1/Reference.cd").toString()); + ASTCDCompilationUnit conCD = + JavaLoader.parseCD(EVALUATION_ROOT.resolve("testcase_1/Concrete.cd").toString()); + Set mappings = Set.of("stud", "prof"); + Map contexts = new java.util.LinkedHashMap<>(); + for (String mapping : mappings) { + contexts.put( + mapping, + new ManualIncarnationContextBuilder( + CDModelIndex.of(refCD), CDModelIndex.of(conCD), confParams) + .buildContextForMapping(mapping)); + } + + assertDoesNotThrow( + () -> + AdaptationConflictDetector.validate( + CDModelIndex.of(refCD), + CDModelIndex.of(conCD), + mappings, + contexts, + confParams, + false)); + } + + @Test + public void derivesAttributeForEachMappings() { + IncarnationContext context = context("ForEachAttributeRef.cd", "ForEachAttributeConc.cd"); + + assertEquals( + 2, + context + .getIncarnations(StableElementKey.field("Builder", "attribute", "any")) + .size()); + } + + @Test + public void derivesMethodForEachMappingsFromAttributeIncarnations() { + IncarnationContext context = context("ForEachMethodRef.cd", "ForEachMethodConc.cd"); + + assertEquals( + 2, + context + .getIncarnations(StableElementKey.method("DataClass", "getAttribute", List.of(), "any")) + .size()); + } + + @Test + public void derivesExactMethodForEachMappingsFromAttributeIncarnations() { + IncarnationContext context = + context("ForEachMethodExactRef.cd", "ForEachMethodExactConc.cd"); + + assertEquals( + 2, + context + .getIncarnations(StableElementKey.method("Builder", "copy", List.of(), "any")) + .size()); + } + + @Test + public void doesNotDeriveMethodForEachMappingsFromAccidentalSubstrings() { + IncarnationContext context = + context("ForEachMethodSubstringRef.cd", "ForEachMethodSubstringConc.cd"); + + assertEquals( + 0, + context + .getIncarnations( + StableElementKey.method("DataClass", "getAttributable", List.of(), "any")) + .size()); + } + + @Test + public void derivesTypeForEachMappings() { + IncarnationContext context = context("ForEachTypeRef.cd", "ForEachTypeConc.cd"); + + assertEquals(2, context.getIncarnations(StableElementKey.type("DataClassBuilder")).size()); + } + + @Test + public void detectsMissingForEachMappingBeforeCleaningExistingOutput() throws IOException { + Path output = Path.of("target/codeAdapter/forEachConflictPreserve"); + Files.createDirectories(output); + Path marker = output.resolve("marker.txt"); + Files.writeString(marker, "keep"); + + CodeAdapter adapter = + new CodeAdapter( + Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE), + confParams); + + CodeAdaptationException exception = + assertThrows( + CodeAdaptationException.class, + () -> + adapter.adapt( + ROOT.resolve("ForEachMissingRef.cd").toFile(), + ROOT.resolve("ForEachMissingConc.cd").toFile(), + MAPPINGS, + ROOT.resolve("adapter"), + ROOT.resolve("concrete"), + output, + false, + true)); + + assertTrue(exception.getMessage().contains("missing forEach incarnation")); + assertTrue(Files.exists(marker), "Conflict detection must run before output cleanup"); + } + + @Test + public void codeAdapterFailsBeforeCleaningExistingOutput() throws IOException { + Path output = Path.of("target/codeAdapter/conflictDetectorPreserve"); + Files.createDirectories(output); + Path marker = output.resolve("marker.txt"); + Files.writeString(marker, "keep"); + + CodeAdapter adapter = + new CodeAdapter( + Set.of(NAME_MATCHING, ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR, IGNORE_NON_MATCHED_TYPE), + confParams); + + assertThrows( + CodeAdaptationException.class, + () -> + adapter.adapt( + ROOT.resolve("AnyRef.cd").toFile(), + ROOT.resolve("AnyConc.cd").toFile(), + MAPPINGS, + ROOT.resolve("adapter"), + ROOT.resolve("concrete"), + output, + false, + true)); + + assertTrue(Files.exists(marker), "Conflict detection must run before output cleanup"); + } + + private void assertConflict(String reference, String concrete, String expectedMessagePart) { + CodeAdaptationException exception = + assertThrows(CodeAdaptationException.class, () -> validate(reference, concrete)); + assertTrue( + exception.getMessage().contains(expectedMessagePart), + () -> "Expected message to contain '" + expectedMessagePart + "' but was: " + + exception.getMessage()); + } + + private void validate(String reference, String concrete) { + ASTCDCompilationUnit refCD = JavaLoader.parseCD(ROOT.resolve(reference).toString()); + ASTCDCompilationUnit conCD = JavaLoader.parseCD(ROOT.resolve(concrete).toString()); + IncarnationContext context = context(refCD, conCD); + AdaptationConflictDetector.validate( + CDModelIndex.of(refCD), + CDModelIndex.of(conCD), + MAPPINGS, + Map.of("ref", context), + confParams, + false); + } + + private IncarnationContext context(String reference, String concrete) { + ASTCDCompilationUnit refCD = JavaLoader.parseCD(ROOT.resolve(reference).toString()); + ASTCDCompilationUnit conCD = JavaLoader.parseCD(ROOT.resolve(concrete).toString()); + return context(refCD, conCD); + } + + private IncarnationContext context(ASTCDCompilationUnit refCD, ASTCDCompilationUnit conCD) { + ManualIncarnationContextBuilder builder = + new ManualIncarnationContextBuilder( + CDModelIndex.of(refCD), CDModelIndex.of(conCD), confParams); + return builder.buildContextForMapping("ref"); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationContextBuilderTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationContextBuilderTest.java new file mode 100644 index 00000000..481cfd17 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/handler/multiIncarnation/IncarnationContextBuilderTest.java @@ -0,0 +1,338 @@ +package de.monticore.codeAdaption.handler.multiIncarnation; + +import static de.monticore.cdconformance.CDConfParameter.ALLOW_ADDITIONAL_PARAMETERS; +import static de.monticore.cdconformance.CDConfParameter.INHERITANCE; +import static de.monticore.cdconformance.CDConfParameter.NAME_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STEREOTYPE_MAPPING; +import static de.monticore.cdconformance.CDConfParameter.STRICT_PARAMETER_ORDER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdconcretization.ConcretizationCompleter; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.cdconformance.CDConformanceChecker; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.handler.BasicUpdateHandlerTestAccess; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.cddiff.CDDiffUtil; +import java.io.File; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class IncarnationContextBuilderTest extends AdapterAbstractTest { + private Set confParameters; + + @BeforeEach + public void setup() { + initMills(); + confParameters = + Set.of( + NAME_MAPPING, + INHERITANCE, + STEREOTYPE_MAPPING, + STRICT_PARAMETER_ORDER, + ALLOW_ADDITIONAL_PARAMETERS); + } + + @Test + @DisplayName("Builds owner-aware field mappings from stereotypes") + public void buildsOwnerAwareFieldMappings() { + ASTCDCompilationUnit refCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Reference.cd")); + ASTCDCompilationUnit conCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Concrete.cd")); + + IncarnationContext context = build(refCD, conCD, "buildPat"); + StableElementKey referenceField = StableElementKey.field("Builder", "attribute", "any"); + + List targets = + context.getIncarnations(referenceField).stream() + .map(IncarnationContext.MappedElement::key) + .collect(Collectors.toList()); + + assertTrue(targets.contains(StableElementKey.field("Person", "name", "String"))); + assertTrue(targets.contains(StableElementKey.field("Person", "age", "int"))); + assertTrue(targets.contains(StableElementKey.field("Person", "tags", "List"))); + assertTrue(targets.contains(StableElementKey.field("Task", "status", "String"))); + assertEquals(11, targets.size()); + } + + @Test + @DisplayName("Builds signature-aware method mappings and grouping types") + public void buildsSignatureAwareMethodMappingsAndGroupingTypes() { + ASTCDCompilationUnit refCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Reference.cd")); + ASTCDCompilationUnit conCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Concrete.cd")); + + IncarnationContext context = build(refCD, conCD, "observer"); + StableElementKey referenceMethod = StableElementKey.method("Observer", "update", List.of(), "void"); + + List targets = + context.getIncarnations(referenceMethod).stream() + .map(IncarnationContext.MappedElement::key) + .collect(Collectors.toList()); + + assertTrue( + targets.contains( + StableElementKey.method("PipelineObserver", "onPipelineStage", List.of("String"), "void"))); + assertTrue( + targets.contains( + StableElementKey.method("LoggingObserver", "onPipelineStage", List.of("String"), "void"))); + assertTrue( + targets.contains( + StableElementKey.method("MetricsObserver", "onPipelineStage", List.of("String"), "void"))); + assertEquals( + "PipelineObserver", + context + .getGroupingFor(StableElementKey.type("LoggingObserver")) + .orElseThrow() + .key() + .getName()); + assertEquals( + "PipelineObserver", + context + .getGroupingFor(StableElementKey.type("MetricsObserver")) + .orElseThrow() + .key() + .getName()); + } + + @Test + @DisplayName("Can build mappings from concretization plus conformance without stereotype overlay") + public void buildsCheckerOnlyContextAfterConcretization() throws Exception { + ASTCDCompilationUnit refCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingRef.cd")); + ASTCDCompilationUnit conCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingConc.cd")); + + ConcretizationCompleter completer = new ConcretizationCompleter(confParameters); + completer.completeCD(conCD, refCD, "ref"); + + CDConformanceChecker checker = new CDConformanceChecker(confParameters); + assertTrue(checker.checkConformance(conCD, refCD, "ref")); + + IncarnationContext context = + new IncarnationContextBuilder(checker, CDModelIndex.of(refCD), CDModelIndex.of(conCD)) + .buildContextForMapping("ref", false); + + ASTCDType referenceCourse = findType(refCD, "Course"); + List incarnations = + context.getIncarnations(StableElementKey.type(referenceCourse)).stream() + .map(element -> element.key().getName()) + .collect(Collectors.toList()); + + assertEquals(List.of("Course"), incarnations); + } + + @Test + @DisplayName("Can disable manual stereotype overlay when checker mappings are absent") + public void canDisableManualStereotypeOverlay() { + ASTCDCompilationUnit refCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Reference.cd")); + ASTCDCompilationUnit conCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Concrete.cd")); + CDConformanceChecker checker = new CDConformanceChecker(confParameters); + + IncarnationContext checkerOnly = + new IncarnationContextBuilder(checker, CDModelIndex.of(refCD), CDModelIndex.of(conCD)) + .buildContextForMapping("observer", false); + IncarnationContext manualFallback = + new IncarnationContextBuilder(checker, CDModelIndex.of(refCD), CDModelIndex.of(conCD)) + .buildContextForMapping("observer", true); + + assertTrue(checkerOnly.getMappings().isEmpty()); + assertFalse(manualFallback.getMappings().isEmpty()); + } + + @Test + @DisplayName("Common-parent switch controls whether concrete incarnations collapse to a grouping type") + public void commonParentSwitchControlsGroupingResolution() { + ASTCDCompilationUnit refCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Reference.cd")); + ASTCDCompilationUnit conCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Concrete.cd")); + + ASTCDType observer = findType(refCD, "Observer"); + ASTCDType pipelineObserver = findType(conCD, "PipelineObserver"); + ASTCDType loggingObserver = findType(conCD, "LoggingObserver"); + ASTCDType metricsObserver = findType(conCD, "MetricsObserver"); + + Map> mappings = + new LinkedHashMap<>(); + mappings.put( + StableElementKey.type(observer), + List.of( + new IncarnationContext.MappedElement( + StableElementKey.type(loggingObserver), loggingObserver.getSymbol()), + new IncarnationContext.MappedElement( + StableElementKey.type(metricsObserver), metricsObserver.getSymbol()))); + + IncarnationContext.MappedElement grouping = + new IncarnationContext.MappedElement( + StableElementKey.type(pipelineObserver), pipelineObserver.getSymbol()); + + IncarnationContext context = + new IncarnationContext( + "observer", + mappings, + Map.of( + StableElementKey.type(loggingObserver), grouping, + StableElementKey.type(metricsObserver), grouping)); + + assertEquals( + "PipelineObserver", + resolve(context, null, null, Map.of(), true, observer.getSymbol()).orElseThrow().getName()); + assertEquals( + "LoggingObserver", + resolve(context, null, null, Map.of(), false, observer.getSymbol()).orElseThrow().getName()); + } + + @Test + @DisplayName("Stable keys resolve mappings across separately parsed equivalent CDs") + public void resolvesMappingsAcrossSeparateParses() { + File referenceFile = + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Reference.cd"); + File concreteFile = + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Concrete.cd"); + ASTCDCompilationUnit firstReference = JavaLoader.loadCD(referenceFile); + ASTCDCompilationUnit firstConcrete = JavaLoader.loadCD(concreteFile); + IncarnationContext context = build(firstReference, firstConcrete, "buildPat"); + + ASTCDCompilationUnit secondReference = JavaLoader.loadCD(referenceFile); + CDModelIndex secondIndex = CDModelIndex.of(secondReference); + ASTCDType secondBuilder = findType(secondReference, "Builder"); + StableElementKey typeKey = + StableElementKey.fromSymbol(secondBuilder.getSymbol(), secondIndex).orElseThrow(); + StableElementKey fieldKey = + StableElementKey.fromSymbol( + secondBuilder.getCDAttributeList().get(0).getSymbol(), secondIndex) + .orElseThrow(); + StableElementKey methodKey = + StableElementKey.fromSymbol( + secondBuilder.getCDMethodList().get(0).getSymbol(), secondIndex) + .orElseThrow(); + + assertFalse(context.getIncarnations(typeKey).isEmpty()); + assertEquals(11, context.getIncarnations(fieldKey).size()); + assertFalse(context.getIncarnations(methodKey).isEmpty()); + assertThrows( + UnsupportedOperationException.class, + () -> context.getMappings().put(StableElementKey.type("Other"), List.of())); + assertThrows( + UnsupportedOperationException.class, + () -> context.getIncarnations(fieldKey).clear()); + } + + @Test + @DisplayName("Pass selection resolves types and members by stable key across separate parses") + public void passSelectionUsesStableKeysAndSelectedOwner() { + File referenceFile = + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Reference.cd"); + File concreteFile = + new File( + "src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Concrete.cd"); + ASTCDCompilationUnit contextReference = JavaLoader.loadCD(referenceFile); + ASTCDCompilationUnit concrete = JavaLoader.loadCD(concreteFile); + IncarnationContext context = build(contextReference, concrete, "buildPat"); + + IncarnationContext.MappedElement selectedTask = + context.getIncarnations(StableElementKey.type("Builder")).stream() + .filter(element -> element.key().equals(StableElementKey.type("Task"))) + .findFirst() + .orElseThrow(); + ASTCDCompilationUnit separatelyParsedReference = JavaLoader.loadCD(referenceFile); + ASTCDType builder = findType(separatelyParsedReference, "Builder"); + Map selection = + Map.of(StableElementKey.type("Builder"), selectedTask); + assertEquals( + "Task", + resolve(context, separatelyParsedReference, concrete, selection, false, builder.getSymbol()) + .orElseThrow() + .getName()); + var selectedField = + resolve( + context, + separatelyParsedReference, + concrete, + selection, + false, + builder.getCDAttributeList().get(0).getSymbol()) + .orElseThrow(); + assertEquals( + "Task", + StableElementKey.fromSymbol(selectedField, CDModelIndex.of(concrete)) + .orElseThrow() + .getOwnerType() + .orElseThrow()); + } + + private IncarnationContext build(ASTCDCompilationUnit refCD, ASTCDCompilationUnit conCD, String mapping) { + CDConformanceChecker checker = new CDConformanceChecker(confParameters); + try { + checker.checkConformance(conCD, refCD, mapping); + } catch (Throwable ignored) { + // The context builder must still overlay stereotypes when conformance is partial. + } + return new IncarnationContextBuilder(checker, CDModelIndex.of(refCD), CDModelIndex.of(conCD)) + .buildContextForMapping(mapping); + } + + private ASTCDType findType(ASTCDCompilationUnit cd, String name) { + return CDDiffUtil.getAllCDTypes(cd).stream() + .filter(type -> type.getName().equals(name)) + .findFirst() + .orElseThrow(); + } + + private static Optional resolve( + IncarnationContext incarnationContext, + ASTCDCompilationUnit reference, + ASTCDCompilationUnit concrete, + Map selection, + boolean useCommonParentForMultipleIncarnations, + de.monticore.symboltable.ISymbol symbol) { + return BasicUpdateHandlerTestAccess.resolve( + incarnationContext, + reference, + concrete, + selection, + useCommonParentForMultipleIncarnations, + symbol); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/AnnotMatcherTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/AnnotMatcherTest.java index 711f5ea3..aeffcde7 100644 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/AnnotMatcherTest.java +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/AnnotMatcherTest.java @@ -1,16 +1,22 @@ package de.monticore.codeAdaption.matcher; +import de.monticore.codeAdaption.matcher.annotMatcher.AnnotVariableMatcher; import de.monticore.codeAdaption.utils.AdapterParam; +import de.monticore.codeAdaption.utils.JavaLoader; import de.monticore.codeAdaption.validator.CodeValidator; import de.monticore.java.javadsl._ast.ASTFieldDeclaration; import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; import de.monticore.java.javadsl._ast.ASTTypeDeclaration; import de.monticore.javalight._ast.ASTMethodDeclaration; import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import java.io.File; +import java.util.List; import java.util.Optional; import java.util.Set; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; class AnnotMatcherTest extends MatcherAbstractTest { private CodeValidator validator; @@ -21,75 +27,82 @@ public void init(String javaFile) { validator = new CodeValidator(cd, Set.of(AdapterParam.ANNOTATION_MATCHING)); } - @Test - public void TestTypeAnnotationMatching() { - init("/annotMatcher/EntityRepository.java"); - ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); - Optional matching = validator.getMatchedType(entityRepos); - - Assertions.assertTrue(matching.isPresent()); - Assertions.assertEquals(1, matching.get().getReferences().size()); - Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); - Assertions.assertEquals("${}Repository", matching.get().getTemplate()); - Assertions.assertTrue(matching.get().mustBePerform()); - } - - @Test - public void TestMethodAnnotationMatching() { + @ParameterizedTest(name = "annotation matching for {0}") + @ValueSource(strings = {"type", "method", "field", "local", "parameter"}) + void matchesAnnotatedElements(String elementKind) { init("/annotMatcher/EntityRepository.java"); - ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); - ASTMethodDeclaration method = collector.getAllMethodDeclarations(entityRepos).get(0); + ASTTypeDeclaration type = collector.getAllTypeDeclarations().get(0); + ExpectedMatching expected = expectedMatching(elementKind, type); + Optional matching = expected.matching(); - Optional matching = validator.getMatchedMethod(entityRepos, method); Assertions.assertTrue(matching.isPresent()); - Assertions.assertEquals(2, matching.get().getReferences().size()); - Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); - Assertions.assertEquals("id", matching.get().getReferences().get(1).getName()); - Assertions.assertEquals("find${}By${cap_first}", matching.get().getTemplate()); + Assertions.assertEquals( + expected.referenceNames(), + matching.get().getReferences().stream().map(value -> value.getName()).toList()); + Assertions.assertEquals(expected.template(), matching.get().getTemplate()); Assertions.assertTrue(matching.get().mustBePerform()); } @Test - public void TestAttributeAnnotationMatching() { + void variableMatcherUsesReplacedReferenceCD() { init("/annotMatcher/EntityRepository.java"); - ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); - ASTFieldDeclaration attribute = collector.getAllFieldDeclarations(entityRepos).get(0); + var unrelatedCD = + JavaLoader.loadCD( + new File( + "src/test/resources/de/monticore/codeAdaption/validator/Validator.cd")); + AnnotVariableMatcher matcher = new AnnotVariableMatcher(unrelatedCD); + matcher.setReferenceCD(cd); - Optional matching = validator.getMatchedField(entityRepos, attribute); - Assertions.assertTrue(matching.isPresent()); - Assertions.assertEquals(1, matching.get().getReferences().size()); - Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); - Assertions.assertEquals("${uncap_first}Set", matching.get().getTemplate()); - Assertions.assertTrue(matching.get().mustBePerform()); - } - - @Test - public void TestLocalVariableAnnotationMatching() { - init("/annotMatcher/EntityRepository.java"); ASTTypeDeclaration type = collector.getAllTypeDeclarations().get(0); ASTMethodDeclaration method = collector.getAllMethodDeclarations(type).get(2); - ASTLocalVariableDeclaration localVar = collector.getAllLocVariables(type, method).get(0); + ASTLocalVariableDeclaration local = collector.getAllLocVariables(type, method).get(0); + Optional matching = matcher.getMatchedLocalVariable(type, method, local); - Optional matching = validator.getMatchedLocalVariable(type, method, localVar); Assertions.assertTrue(matching.isPresent()); - Assertions.assertEquals(1, matching.get().getReferences().size()); - Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); - Assertions.assertEquals("${uncap_first}List", matching.get().getTemplate()); - Assertions.assertTrue(matching.get().mustBePerform()); + Assertions.assertEquals( + List.of("Entity"), + matching.get().getReferences().stream().map(value -> value.getName()).toList()); } - @Test - public void TestFormalParameterAnnotationMatching() { - init("/annotMatcher/EntityRepository.java"); - ASTTypeDeclaration type = collector.getAllTypeDeclarations().get(0); - ASTMethodDeclaration method = collector.getAllMethodDeclarations(type).get(3); - ASTFormalParameter param = collector.getAllParameters(type, method).get(0); - - Optional matching = validator.getMatchedParameter(type, method, param); - Assertions.assertTrue(matching.isPresent()); - Assertions.assertEquals(1, matching.get().getReferences().size()); - Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); - Assertions.assertEquals("${uncap_first}", matching.get().getTemplate()); - Assertions.assertTrue(matching.get().mustBePerform()); + private ExpectedMatching expectedMatching(String elementKind, ASTTypeDeclaration type) { + return switch (elementKind) { + case "type" -> + new ExpectedMatching( + validator.getMatchedType(type), List.of("Entity"), "${}Repository"); + case "method" -> { + ASTMethodDeclaration method = collector.getAllMethodDeclarations(type).get(0); + yield new ExpectedMatching( + validator.getMatchedMethod(type, method), + List.of("Entity", "id"), + "find${}By${cap_first}"); + } + case "field" -> { + ASTFieldDeclaration field = collector.getAllFieldDeclarations(type).get(0); + yield new ExpectedMatching( + validator.getMatchedField(type, field), + List.of("Entity"), + "${uncap_first}Set"); + } + case "local" -> { + ASTMethodDeclaration method = collector.getAllMethodDeclarations(type).get(2); + ASTLocalVariableDeclaration local = collector.getAllLocVariables(type, method).get(0); + yield new ExpectedMatching( + validator.getMatchedLocalVariable(type, method, local), + List.of("Entity"), + "${uncap_first}List"); + } + case "parameter" -> { + ASTMethodDeclaration method = collector.getAllMethodDeclarations(type).get(3); + ASTFormalParameter parameter = collector.getAllParameters(type, method).get(0); + yield new ExpectedMatching( + validator.getMatchedParameter(type, method, parameter), + List.of("Entity"), + "${uncap_first}"); + } + default -> throw new IllegalArgumentException("Unknown element kind: " + elementKind); + }; } + + private record ExpectedMatching( + Optional matching, List referenceNames, String template) {} } diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/InfixMatcherTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/InfixMatcherTest.java index b454a55e..62f7205e 100644 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/InfixMatcherTest.java +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/InfixMatcherTest.java @@ -3,12 +3,15 @@ import static de.monticore.codeAdaption.utils.AdapterParam.INFIX_MATCHING; import de.monticore.codeAdaption.validator.CodeValidator; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.cdbasis._ast.ASTCDType; import de.monticore.java.javadsl._ast.ASTFieldDeclaration; import de.monticore.java.javadsl._ast.ASTLocalVariableDeclaration; import de.monticore.java.javadsl._ast.ASTTypeDeclaration; import de.monticore.javalight._ast.ASTMethodDeclaration; import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; import java.util.Optional; +import java.util.List; import java.util.Set; import org.junit.jupiter.api.*; @@ -92,4 +95,61 @@ public void TestFormalParameterAnnotationMatching() { Assertions.assertEquals("${uncap_first}", matching.get().getTemplate()); Assertions.assertTrue(matching.get().mustBePerform()); } + + @Test + void repeatedInfixesProduceOneReferencePerPlaceholder() { + init("/infixMatcher/EntityRepository.java"); + ASTCDType entity = + AdapterUtils.getAllCDTypes(cd).stream() + .filter(type -> "Entity".equals(type.getName())) + .findFirst() + .orElseThrow(); + + CodeMatching matching = + MatcherHelper.mkMatchingFromInfixRef( + List.of(entity.getSymbol()), "EntityToEntity") + .orElseThrow(); + + Assertions.assertEquals("${}To${}", matching.getTemplate()); + Assertions.assertEquals(2, matching.getReferences().size()); + Assertions.assertEquals( + "EntityToEntity", + MatcherHelper.fillTemplate(matching.getTemplate(), matching.getReferences())); + } + + @Test + void referencesAreOrderedByTheirNonOverlappingPositions() { + init("/infixMatcher/EntityRepository.java"); + ASTCDType entity = + AdapterUtils.getAllCDTypes(cd).stream() + .filter(type -> "Entity".equals(type.getName())) + .findFirst() + .orElseThrow(); + ASTCDType application = + AdapterUtils.getAllCDTypes(cd).stream() + .filter(type -> "Application".equals(type.getName())) + .findFirst() + .orElseThrow(); + + List references = + MatcherHelper.cleanReferences( + "EntityApplicationEntity", List.of(application.getSymbol(), entity.getSymbol())); + + Assertions.assertEquals(List.of("Entity", "Application", "Entity"), + references.stream().map(de.monticore.symboltable.ISymbol::getName).toList()); + } + + @Test + void unmatchedTemplatePlaceholdersRemainVisible() { + init("/infixMatcher/EntityRepository.java"); + ASTCDType entity = + AdapterUtils.getAllCDTypes(cd).stream() + .filter(type -> "Entity".equals(type.getName())) + .findFirst() + .orElseThrow(); + + Assertions.assertEquals( + "Entity${cap_first}", + MatcherHelper.fillTemplate("${}${cap_first}", List.of(entity.getSymbol()))); + } } diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CD4CodeTestGenerator.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CD4CodeTestGenerator.java new file mode 100644 index 00000000..585ce136 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CD4CodeTestGenerator.java @@ -0,0 +1,89 @@ +package de.monticore.codeAdaption.testutil; + +import de.monticore.CD4CodeTool; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.se_rwth.commons.logging.Log; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import spoon.Launcher; +import spoon.reflect.code.CtComment; +import spoon.reflect.visitor.filter.TypeFilter; + +/** Generates CD4Code fixtures used by evaluation tests. */ +public final class CD4CodeTestGenerator { + + private CD4CodeTestGenerator() {} + + public static void generate(File cdFile, Path hwcPath, Path output) { + String[] input = { + "-i", + cdFile.getAbsolutePath(), + "-ct", + "cd2java.CD2Java", + "--gen", + "-hwc", + hwcPath.toString(), + "-o", + output.toString(), + "--fieldfromrole", + "navigable" + }; + CD4CodeTool.main(input); + + JavaLoader.readJavaFile(output).forEach(CD4CodeTestGenerator::removeComments); + } + + private static void removeComments(File file) { + Path tempDir = null; + try { + tempDir = Files.createTempDirectory("ref-code-adaptation-comments"); + Launcher launcher = new Launcher(); + launcher.getEnvironment().setNoClasspath(true); + launcher.addInputResource(file.getAbsolutePath()); + launcher.buildModel(); + List comments = + new ArrayList<>(launcher.getModel().getElements(new TypeFilter<>(CtComment.class))); + comments.forEach(CtComment::delete); + launcher.setSourceOutputDirectory(tempDir.toFile()); + launcher.prettyprint(); + + Optional generated; + try (var paths = Files.walk(tempDir)) { + generated = + paths + .filter(Files::isRegularFile) + .filter(path -> path.getFileName().toString().equals(file.getName())) + .findFirst(); + } + if (generated.isPresent()) { + Files.copy(generated.get(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); + } else { + Log.warn("Spoon did not produce a rewritten file for " + file.getAbsolutePath()); + } + } catch (Exception exception) { + Log.error("It was not possible to remove comments from " + file.getAbsolutePath(), exception); + } finally { + deleteTemporaryDirectory(tempDir); + } + } + + private static void deleteTemporaryDirectory(Path tempDir) { + if (tempDir == null) { + return; + } + try (var paths = Files.walk(tempDir)) { + for (Path path : paths.sorted(Comparator.reverseOrder()).toList()) { + Files.deleteIfExists(path); + } + } catch (IOException exception) { + Log.warn("Could not delete temporary comment-cleanup directory " + tempDir); + } + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CDConcretizationFixtureWorkspace.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CDConcretizationFixtureWorkspace.java new file mode 100644 index 00000000..36d7cdb4 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CDConcretizationFixtureWorkspace.java @@ -0,0 +1,209 @@ +package de.monticore.codeAdaption.testutil; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +/** Builds isolated Java fixture directories for cdconcretization tests. */ +public final class CDConcretizationFixtureWorkspace { + + private static final Path RESOURCE_ROOT = Path.of(CDConcretizationTestCase.RESOURCE_ROOT); + private static final Path SHARED_JAVA_ROOT = RESOURCE_ROOT.resolve("_shared").resolve("java"); + private static final Path INDEX = RESOURCE_ROOT.resolve("_shared").resolve("shared-fixtures.tsv"); + private static final Path WORKSPACE_ROOT = Path.of("target/test-fixtures/cdconcretization"); + private static final Pattern PACKAGE_DECLARATION = + Pattern.compile("^\\s*package\\s+[^;\\r\\n]+;\\s*$"); + private static final Pattern PACKAGE_LINE_IN_SOURCE = + Pattern.compile("(?m)^\\s*package\\s+[^;\\r\\n]+;"); + + private static final Map> ENTRIES_BY_CASE = loadIndex(); + + private CDConcretizationFixtureWorkspace() {} + + public static CDConcretizationTestCase materialize(CDConcretizationTestCase testCase) { + Path caseRoot = safeResolve(WORKSPACE_ROOT, testCase.id()); + Path adapterTarget = caseRoot.resolve("adapter"); + Path concreteTarget = caseRoot.resolve("concrete"); + + try { + deleteRecursively(caseRoot); + Files.createDirectories(adapterTarget); + Files.createDirectories(concreteTarget); + + Set sharedOutputs = new LinkedHashSet<>(); + for (SharedFixtureEntry entry : + ENTRIES_BY_CASE.getOrDefault(relativeConcreteCd(testCase), List.of())) { + Path roleTarget = roleTarget(entry.role(), adapterTarget, concreteTarget); + String outputKey = entry.role() + ":" + normalizeRelative(entry.output()); + if (!sharedOutputs.add(outputKey)) { + throw new IllegalStateException( + "Duplicate shared fixture output for " + relativeConcreteCd(testCase) + ": " + outputKey); + } + writeSharedFixture(entry, roleTarget); + } + + copyLocalOverlay(testCase.adapterPath(), adapterTarget); + copyLocalOverlay(testCase.concretePath(), concreteTarget); + } catch (IOException e) { + throw new IllegalStateException( + "Failed to materialize cdconcretization fixture for " + testCase.displayName(), e); + } + + return new CDConcretizationTestCase( + testCase.id(), + testCase.displayName(), + testCase.refCd(), + testCase.concCd(), + adapterTarget, + concreteTarget, + testCase.outputPath(), + testCase.mappings(), + testCase.strictParameterOrder(), + testCase.enabled()); + } + + private static void writeSharedFixture(SharedFixtureEntry entry, Path roleTarget) + throws IOException { + Path sharedSource = safeResolve(RESOURCE_ROOT, entry.shared()); + if (!sharedSource.startsWith(SHARED_JAVA_ROOT.normalize())) { + throw new IllegalStateException("Shared fixture source is outside _shared/java: " + entry.shared()); + } + if (!Files.isRegularFile(sharedSource)) { + throw new IllegalStateException("Missing shared fixture source: " + entry.shared()); + } + + Path output = safeResolve(roleTarget, entry.output()); + String source = Files.readString(sharedSource, StandardCharsets.UTF_8); + Matcher matcher = PACKAGE_LINE_IN_SOURCE.matcher(source); + if (!matcher.find()) { + throw new IllegalStateException("Shared fixture has no package declaration: " + entry.shared()); + } + + String rendered = matcher.replaceFirst(Matcher.quoteReplacement(entry.packageLine())); + Files.createDirectories(output.getParent()); + Files.writeString(output, rendered, StandardCharsets.UTF_8); + } + + private static void copyLocalOverlay(Path sourceRoot, Path targetRoot) throws IOException { + if (!Files.exists(sourceRoot)) { + return; + } + try (Stream paths = Files.walk(sourceRoot)) { + for (Path source : paths.filter(Files::isRegularFile).sorted().toList()) { + Path relative = sourceRoot.relativize(source); + Path target = safeResolve(targetRoot, relative.toString()); + Files.createDirectories(target.getParent()); + Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); + } + } + } + + private static Map> loadIndex() { + if (!Files.exists(INDEX)) { + return Map.of(); + } + + Map> result = new LinkedHashMap<>(); + Set seenOutputs = new LinkedHashSet<>(); + try { + List lines = Files.readAllLines(INDEX, StandardCharsets.UTF_8); + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + if (line.isBlank() || line.startsWith("#")) { + continue; + } + String[] parts = line.split("\\t", 5); + if (parts.length != 5) { + throw new IllegalStateException("Invalid shared fixture index row " + (i + 1)); + } + + SharedFixtureEntry entry = + new SharedFixtureEntry(parts[0], parts[1], parts[2], parts[3], parts[4]); + validateEntry(entry, i + 1); + + String outputKey = + entry.concreteCd() + + ":" + + entry.role() + + ":" + + normalizeRelative(entry.output()); + if (!seenOutputs.add(outputKey)) { + throw new IllegalStateException("Duplicate shared fixture output in row " + (i + 1)); + } + result.computeIfAbsent(entry.concreteCd(), ignored -> new ArrayList<>()).add(entry); + } + } catch (IOException e) { + throw new IllegalStateException("Failed to read shared fixture index " + INDEX, e); + } + result.replaceAll((ignored, entries) -> List.copyOf(entries)); + return Map.copyOf(result); + } + + private static void validateEntry(SharedFixtureEntry entry, int row) { + safeResolve(RESOURCE_ROOT, entry.concreteCd()); + safeResolve(RESOURCE_ROOT, entry.shared()); + safeResolve(Path.of("unused"), entry.output()); + + if (!entry.role().equals("adapter") && !entry.role().equals("concrete")) { + throw new IllegalStateException("Invalid role in shared fixture index row " + row); + } + if (!PACKAGE_DECLARATION.matcher(entry.packageLine()).matches()) { + throw new IllegalStateException("Invalid package declaration in shared fixture index row " + row); + } + } + + private static Path roleTarget(String role, Path adapterTarget, Path concreteTarget) { + return role.equals("adapter") ? adapterTarget : concreteTarget; + } + + private static String relativeConcreteCd(CDConcretizationTestCase testCase) { + return RESOURCE_ROOT.relativize(testCase.concCd()).toString().replace('\\', '/'); + } + + private static Path safeResolve(Path root, String relativePath) { + if (relativePath == null || relativePath.isBlank()) { + throw new IllegalStateException("Fixture path must not be blank."); + } + Path normalizedRoot = root.normalize(); + Path resolved = normalizedRoot.resolve(relativePath.replace('/', java.io.File.separatorChar)).normalize(); + if (!resolved.startsWith(normalizedRoot)) { + throw new IllegalStateException("Fixture path escapes root: " + relativePath); + } + return resolved; + } + + private static String normalizeRelative(String path) { + return safeResolve(Path.of("unused"), path).toString().replace('\\', '/'); + } + + private static void deleteRecursively(Path path) throws IOException { + Path normalizedRoot = WORKSPACE_ROOT.normalize(); + Path normalizedPath = path.normalize(); + if (!normalizedPath.startsWith(normalizedRoot)) { + throw new IllegalArgumentException("Refusing to delete outside fixture workspace: " + path); + } + if (!Files.exists(normalizedPath)) { + return; + } + try (Stream paths = Files.walk(normalizedPath)) { + for (Path p : paths.sorted(Comparator.reverseOrder()).toList()) { + Files.deleteIfExists(p); + } + } + } + + private record SharedFixtureEntry( + String concreteCd, String role, String shared, String output, String packageLine) {} +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CDConcretizationTestCase.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CDConcretizationTestCase.java new file mode 100644 index 00000000..137e9a08 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CDConcretizationTestCase.java @@ -0,0 +1,27 @@ +package de.monticore.codeAdaption.testutil; + +import java.nio.file.Path; +import java.util.Set; + +/** Describes one cdconcretization adaptation test fixture. */ +public record CDConcretizationTestCase( + String id, + String displayName, + Path refCd, + Path concCd, + Path adapterPath, + Path concretePath, + Path outputPath, + Set mappings, + boolean strictParameterOrder, + boolean enabled) { + + public static final String RESOURCE_ROOT = + "src/test/resources/de/monticore/codeAdaption/cdconcretization/"; + + public static final String OUTPUT_ROOT = "target/adapter/cdconcretization/"; + + public CDConcretizationTestCase { + mappings = Set.copyOf(mappings); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CDConcretizationTestCases.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CDConcretizationTestCases.java new file mode 100644 index 00000000..d1567fab --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/CDConcretizationTestCases.java @@ -0,0 +1,346 @@ +package de.monticore.codeAdaption.testutil; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Stream; + +/** Registry of all cdconcretization adaptation test fixtures. */ +public final class CDConcretizationTestCases { + + private static final Path RESOURCE_ROOT = Path.of(CDConcretizationTestCase.RESOURCE_ROOT); + + private static final Map REF_OVERRIDES = + Map.ofEntries( + Map.entry( + "evaluation/getter-setter/DataModelConc.cd", + "evaluation/getter-setter/GetterRef.cd"), + Map.entry( + "evaluation/builder/DataModelConc.cd", "evaluation/builder/BuilderAndMillRef.cd"), + Map.entry( + "evaluation/mill/LanguageInfrastructureConc.cd", "evaluation/mill/MillRef.cd"), + Map.entry( + "methods/forEach/ForEachAttributeSameReturnTypeClassMIConc.cd", + "methods/forEach/ForEachAttributeSameReturnTypeRef.cd"), + Map.entry( + "types/forEach/ForEachTypeNoTargetIncConc.cd", "types/forEach/ForEachTypeRef.cd"), + Map.entry( + "attributes/forEach/ForEachAttributeInheritanceConc.cd", + "attributes/forEach/ForEachAttributeRef.cd"), + Map.entry( + "attributes/forEach/ForEachAttributeDifferentNameClassMIConc.cd", + "attributes/forEach/ForEachAttributeDifferentNameRef.cd"), + Map.entry( + "evaluation/banking/singleInc/BankingConc.cd", "evaluation/banking/BankingRef.cd"), + Map.entry( + "evaluation/banking/multiInc/BankingConc.cd", "evaluation/banking/BankingRef.cd"), + Map.entry( + "evaluation/banking/usageByExtension/BankingConc.cd", + "evaluation/banking/BankingRef.cd"), + Map.entry( + "evaluation/staticDelegator/attrWorkaround/StaticExistsConc.cd", + "evaluation/staticDelegator/attrWorkaround/StaticDelegatorRef.cd"), + Map.entry( + "evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsConc.cd", + "evaluation/staticDelegator/attrWorkaround/StaticDelegatorRef.cd"), + Map.entry( + "evaluation/observer/mutualObservers/MutualObserversConc.cd", + "evaluation/observer/ObserverRef.cd"), + Map.entry( + "attributes/underspecified/AttributeTypeUnderspecifiedDifferentIncTypesConc.cd", + "attributes/underspecified/AttributeTypeUnderspecifiedRef.cd"), + Map.entry( + "attributes/underspecified/AttributeTypeUnderspecifiedNoIncConc.cd", + "attributes/underspecified/AttributeTypeUnderspecifiedRef.cd"), + Map.entry( + "methods/underspecified/ParameterTypeUnderspecifiedIncarnatedConc.cd", + "methods/underspecified/ParameterTypeUnderspecifiedRef.cd"), + Map.entry( + "methods/underspecified/ParameterTypeUnderspecifiedNoIncConc.cd", + "methods/underspecified/ParameterTypeUnderspecifiedRef.cd"), + Map.entry( + "methods/underspecified/ReturnTypeUnderspecifiedIncarnatedConc.cd", + "methods/underspecified/ReturnTypeUnderspecifiedRef.cd"), + Map.entry( + "methods/underspecified/ReturnTypeUnderspecifiedNoIncConc.cd", + "methods/underspecified/ReturnTypeUnderspecifiedRef.cd"), + Map.entry( + "multipleIncarnation/BothAssocSidesMIOneAssocExistsConc.cd", + "multipleIncarnation/BothAssocSidesMIRef.cd")); + + private static final Set EXPECTED_FAILURE_CASES = + Set.of( + "attributes/underspecified/AttributeTypeUnderspecifiedNoIncConc.cd", + "methods/underspecified/ParameterTypeUnderspecifiedNoIncConc.cd", + "methods/underspecified/ReturnTypeUnderspecifiedNoIncConc.cd"); + + private static final Map UNSUPPORTED_CASES = + Map.of( + "attributes/forEach/ForEachAttributeInheritanceConc.cd", + "Upstream cdconcretization does not derive forEach bindings across inherited attribute owners", + "attributes/forEach/ForEachAttributeNoTargetIncConc.cd", + "Upstream cdconcretization requires unimplemented matchStructure/optional-member semantics", + "evaluation/staticDelegator/StaticDelegatorConc.cd", + "Upstream cdconcretization does not implement method-target forEach completion"); + + private static final Map> MAPPING_OVERRIDES = + Map.of( + "evaluation/observer/mutualObservers/MutualObserversConc.cd", + Set.of("ref1", "ref2")); + + private static final Map STRICT_PARAMETER_ORDER = + Map.ofEntries( + Map.entry("evaluation/builder/DataModelConc.cd", true), + Map.entry("evaluation/getter-setter/DataModelConc.cd", false), + Map.entry("evaluation/visitor/VisitorConc.cd", true), + Map.entry("evaluation/banking2/BankingConc.cd", true), + Map.entry("evaluation/mill/LanguageInfrastructureConc.cd", true), + Map.entry("evaluation/repository/DomainModel.cd", true), + Map.entry("evaluation/crud-backend/DomainModel.cd", true), + Map.entry("evaluation/paper-examples/repository/EcommerceDomain.cd", true), + Map.entry("methods/multiIncarnation/ParameterTypeMIConc.cd", true), + Map.entry("methods/multiIncarnation/ParameterAndReturnTypeMIConc.cd", true), + Map.entry("methods/forEach/ForEachAttributeConc.cd", true), + Map.entry("methods/forEach/ForEachAttributeMultipleParametersConc.cd", true), + Map.entry("methods/forEach/ForEachTypeSameParameterTypeConc.cd", true), + Map.entry("methods/forEach/ForEachTypeSameParameterTypeNoNameMatchConc.cd", true), + Map.entry("evaluation/staticDelegator/StaticDelegatorConc.cd", true), + Map.entry("evaluation/staticDelegator/attrWorkaround/StaticExistsConc.cd", true), + Map.entry("evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsConc.cd", true), + Map.entry("evaluation/transitiveDependencies/TransitiveDependenciesConc.cd", true), + Map.entry("evaluation/crud-backend/CRUDBackendConc.cd", true)); + + private static final Map EXPECTED_OUTPUT_OVERRIDES = + Map.of( + "evaluation/builder/DataModelConc.cd", "evaluation/builder/BuilderAndMillOut.cd", + "evaluation/getter-setter/DataModelConc.cd", "evaluation/getter-setter/GetterOut.cd", + "evaluation/macoco/EmptyConc.cd", "evaluation/macoco/EmptyConcOut.cd", + "evaluation/mill/LanguageInfrastructureConc.cd", "evaluation/mill/MillOut.cd"); + + /** Upstream asserts these completed CDs directly against their reference CDs. */ + private static final Set REFERENCE_AS_EXPECTED_OUTPUT_CASES = + Set.of( + "attributes/valid/AttributesMissingConc.cd", + "attributes/valid/TwoAttributesMissingConc.cd", + "attributes/valid/TwoAttributesMissingOneMatchConc.cd", + "inheritance/MissingInheritanceConc.cd", + "methods/basic/valid/ClassEmptyConc.cd", + "methods/basic/valid/ClassMissingConc.cd", + "methods/basic/valid/MethodMissingConc.cd", + "methods/basic/valid/MultipleMethodsMissingConc.cd"); + + private static final Map STRUCTURAL_ORACLE_EXCLUSIONS = + Map.ofEntries( + Map.entry( + "associations/AssociationMissingSimpleConc.cd", + "Upstream test is disabled until its association semantics issue is clarified"), + Map.entry( + "inheritance/AttributeTypeMismatchConc.cd", + "Upstream cdconcretization incorrectly accepts an inherited attribute with an incompatible type"), + Map.entry( + "evaluation/banking/multiInc/BankingConc.cd", + "Upstream test is disabled because bind mappings are not considered while " + + "completing associations"), + Map.entry( + "evaluation/cross-references/MicroserviceConc.cd", + "Upstream test is disabled because forEach cannot express global cross-incarnation references"), + Map.entry( + "evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsConc.cd", + "Upstream test is disabled because forEach completion is not bidirectional")); + + private CDConcretizationTestCases() {} + + public static List allCases() { + try { + List cases = new ArrayList<>(); + try (Stream paths = Files.walk(RESOURCE_ROOT)) { + paths + .filter(Files::isRegularFile) + .map(RESOURCE_ROOT::relativize) + .map(path -> path.toString().replace('\\', '/')) + .filter(path -> path.endsWith("Conc.cd")) + .sorted() + .forEach(path -> cases.add(buildCase(path))); + } + cases.sort(Comparator.comparing(CDConcretizationTestCase::id)); + return List.copyOf(cases); + } catch (IOException e) { + throw new IllegalStateException("Failed to discover cdconcretization test cases", e); + } + } + + static CDConcretizationTestCase buildCase(String concRelativePath) { + String refRelativePath = resolveRefPath(concRelativePath); + String caseBase = concRelativePath.substring(concRelativePath.lastIndexOf('/') + 1); + caseBase = caseBase.substring(0, caseBase.length() - "Conc.cd".length()); + String id = concRelativePath.replace('/', '_').replace(".cd", ""); + + Path refCd = RESOURCE_ROOT.resolve(refRelativePath); + Path concCd = RESOURCE_ROOT.resolve(concRelativePath); + + boolean sharedRef = !parent(refRelativePath).equals(parent(concRelativePath)); + boolean sharedReferenceFile = refRelativePath.endsWith("Reference.cd"); + + Path adapterPath; + if (sharedRef || sharedReferenceFile) { + adapterPath = resolveDirectory(parent(refRelativePath)).resolve("adapter"); + } else { + adapterPath = + resolveDirectory(parent(concRelativePath)).resolve("adapter").resolve(caseBase); + } + + Path concretePath; + if (sharedRef) { + concretePath = resolveDirectory(parent(concRelativePath)).resolve("concrete").resolve(caseBase); + } else if (sharedReferenceFile) { + concretePath = + resolveDirectory(parent(concRelativePath)).resolve("concrete").resolve(caseBase); + } else { + concretePath = resolveDirectory(parent(concRelativePath)).resolve("concrete"); + } + + Path outputPath = Path.of(CDConcretizationTestCase.OUTPUT_ROOT + id); + + return new CDConcretizationTestCase( + id, + concRelativePath.replace("Conc.cd", ""), + refCd, + concCd, + adapterPath, + concretePath, + outputPath, + MAPPING_OVERRIDES.getOrDefault(concRelativePath, Set.of("ref")), + STRICT_PARAMETER_ORDER.getOrDefault(concRelativePath, false), + !EXPECTED_FAILURE_CASES.contains(concRelativePath) + && !UNSUPPORTED_CASES.containsKey(concRelativePath)); + } + + public static List enabledCases() { + String requestedCase = System.getenv("CDCONCRETIZATION_CASE"); + Set requestedCases = + requestedCase == null || requestedCase.isBlank() + ? Set.of() + : Set.of(requestedCase.split(",")); + return allCases().stream() + .filter(CDConcretizationTestCase::enabled) + .filter( + testCase -> + requestedCases.isEmpty() + || requestedCases.contains(testCase.id()) + || requestedCases.contains(testCase.displayName())) + .toList(); + } + + public static List expectedFailureCases() { + return allCases().stream() + .filter(testCase -> EXPECTED_FAILURE_CASES.contains(relativeConcretePath(testCase))) + .toList(); + } + + public static List unsupportedCases() { + return allCases().stream() + .filter(testCase -> UNSUPPORTED_CASES.containsKey(relativeConcretePath(testCase))) + .toList(); + } + + public static String unsupportedReason(CDConcretizationTestCase testCase) { + return UNSUPPORTED_CASES.get(relativeConcretePath(testCase)); + } + + public static Optional expectedOutputModel(CDConcretizationTestCase testCase) { + String concretePath = relativeConcretePath(testCase); + if (STRUCTURAL_ORACLE_EXCLUSIONS.containsKey(concretePath)) { + return Optional.empty(); + } + if (REFERENCE_AS_EXPECTED_OUTPUT_CASES.contains(concretePath)) { + return Optional.of(testCase.refCd()); + } + String expectedPath = + EXPECTED_OUTPUT_OVERRIDES.getOrDefault( + concretePath, concretePath.replace("Conc.cd", "Out.cd")); + Path expected = RESOURCE_ROOT.resolve(expectedPath); + return Files.isRegularFile(expected) ? Optional.of(expected) : Optional.empty(); + } + + public static Optional noExpectedOutputReason(CDConcretizationTestCase testCase) { + return Optional.ofNullable(STRUCTURAL_ORACLE_EXCLUSIONS.get(relativeConcretePath(testCase))); + } + + static String resolveRefPath(String concRelativePath) { + if (REF_OVERRIDES.containsKey(concRelativePath)) { + return REF_OVERRIDES.get(concRelativePath); + } + + String concDir = parent(concRelativePath); + String caseBase = + concRelativePath + .substring(concRelativePath.lastIndexOf('/') + 1) + .replace("Conc.cd", ""); + + String pairedRef = concDir.isEmpty() ? caseBase + "Ref.cd" : concDir + "/" + caseBase + "Ref.cd"; + if (Files.exists(RESOURCE_ROOT.resolve(pairedRef))) { + return pairedRef; + } + + String localReference = concDir.isEmpty() ? "Reference.cd" : concDir + "/Reference.cd"; + if (Files.exists(RESOURCE_ROOT.resolve(localReference))) { + return localReference; + } + + String parentReference = + parent(concDir).isEmpty() ? "Reference.cd" : parent(concDir) + "/Reference.cd"; + if (Files.exists(RESOURCE_ROOT.resolve(parentReference))) { + return parentReference; + } + + String singleRefInDir = findSingleRefInDirectory(concDir); + if (singleRefInDir != null) { + return singleRefInDir; + } + + throw new IllegalStateException( + "Could not resolve reference CD for concrete fixture: " + concRelativePath); + } + + private static String findSingleRefInDirectory(String concDir) { + Path directory = resolveDirectory(concDir); + if (!Files.isDirectory(directory)) { + return null; + } + try (Stream refs = Files.list(directory)) { + List refFiles = + refs.map(Path::getFileName) + .map(Path::toString) + .filter(name -> name.endsWith("Ref.cd")) + .sorted() + .toList(); + if (refFiles.size() == 1) { + return concDir.isEmpty() ? refFiles.get(0) : concDir + "/" + refFiles.get(0); + } + } catch (IOException ignored) { + return null; + } + return null; + } + + private static String parent(String relativePath) { + int slash = relativePath.lastIndexOf('/'); + return slash < 0 ? "" : relativePath.substring(0, slash); + } + + private static String relativeConcretePath(CDConcretizationTestCase testCase) { + return testCase.concCd().toString() + .replace('\\', '/') + .replace(CDConcretizationTestCase.RESOURCE_ROOT, ""); + } + + private static Path resolveDirectory(String relativeDir) { + return relativeDir.isEmpty() ? RESOURCE_ROOT : RESOURCE_ROOT.resolve(relativeDir); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/GeneratedJavaStructureOracle.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/GeneratedJavaStructureOracle.java new file mode 100644 index 00000000..00a9a285 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/testutil/GeneratedJavaStructureOracle.java @@ -0,0 +1,305 @@ +package de.monticore.codeAdaption.testutil; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdinterfaceandenum._ast.ASTCDEnum; +import de.monticore.codeAdaption.utils.CDModelIndex; +import de.monticore.codeAdaption.utils.CDTypeRelations; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.JavaSourceNames; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTClassDeclaration; +import de.monticore.java.javadsl._ast.ASTEnumConstantDeclaration; +import de.monticore.java.javadsl._ast.ASTEnumDeclaration; +import de.monticore.java.javadsl._ast.ASTInterfaceDeclaration; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.java.javadsl._visitor.JavaDSLVisitor2; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** Structural oracle for Java-expressible elements materialized in adapter output. */ +public final class GeneratedJavaStructureOracle { + + private GeneratedJavaStructureOracle() {} + + public static void assertMatches( + Path originalConcreteCd, Path expectedOutputCd, List generatedJava) { + CDModelIndex original = CDModelIndex.of(JavaLoader.parseCD(originalConcreteCd.toString())); + CDModelIndex expected = CDModelIndex.of(JavaLoader.parseCD(expectedOutputCd.toString())); + Map> generatedBySimpleName = new LinkedHashMap<>(); + for (Path source : generatedJava) { + ASTOrdinaryCompilationUnit unit = JavaLoader.loadJava(source.toFile()); + JavaAstElemCollector collector = collect(unit); + for (ASTTypeDeclaration type : unit.getTypeDeclarationList()) { + generatedBySimpleName + .computeIfAbsent(type.getName(), ignored -> new ArrayList<>()) + .add(GeneratedType.from(type, collector, source)); + } + } + + for (ASTCDType expectedType : expected.types()) { + ASTCDType originalType = original.type(expectedType.getName()).orElse(null); + List candidates = + generatedBySimpleName.getOrDefault(expectedType.getName(), List.of()); + if (candidates.isEmpty()) { + // Types without handwritten/adapted Java are supplied later by CD4Code and are represented + // by strict compilation stubs rather than adapter output. When a type is materialized here, + // all completion deltas below are mandatory. + continue; + } + if (candidates.size() > 1) { + fail( + "Expected type '" + + expectedType.getName() + + "' is ambiguous in generated Java: " + + candidates.stream().map(GeneratedType::source).toList()); + } + assertType(originalType, expectedType, candidates.get(0)); + } + } + + private static void assertType( + ASTCDType original, ASTCDType expected, GeneratedType actual) { + String context = expected.getName() + " in " + actual.source(); + assertEquals(kind(expected), actual.kind(), "Wrong type kind for " + context); + + Map originalFields = fields(original); + Map expectedFields = new LinkedHashMap<>(); + expected + .getCDAttributeList() + .forEach( + field -> + expectedFields.put( + field.getName(), JavaSourceNames.printNormalizedFieldType(field))); + expectedFields.forEach( + (name, type) -> + { + if (!type.equals(originalFields.get(name))) { + assertEquals( + type, + actual.fields().get(name), + "Missing or mistyped completed field '" + name + "' on " + context); + } + }); + + Map originalMethods = methods(original); + Map expectedMethods = new LinkedHashMap<>(); + expected + .getCDMethodList() + .forEach( + method -> + expectedMethods.put( + JavaSourceNames.methodSignature(method), + JavaSourceNames.printNormalizedReturnType(method))); + expectedMethods.forEach( + (signature, returnType) -> + { + if (!returnType.equals(originalMethods.get(signature))) { + assertEquals( + returnType, + actual.methods().get(signature), + "Missing or mistyped completed method '" + signature + "' on " + context); + } + }); + + String originalSuperclass = + original == null + ? null + : CDTypeRelations.firstSuperclassName(original) + .map(JavaSourceNames::simpleName) + .orElse(null); + String expectedSuperclass = + expected.getSuperclassList().size() == 1 + ? CDTypeRelations.firstSuperclassName(expected) + .map(JavaSourceNames::simpleName) + .orElse(null) + : null; + if (expected.getSuperclassList().size() <= 1 + && !java.util.Objects.equals(originalSuperclass, expectedSuperclass)) { + assertEquals(expectedSuperclass, actual.superclass(), "Wrong completed superclass for " + context); + } + Set originalInterfaces = interfaces(original); + Set expectedInterfaces = + CDTypeRelations.interfaceNames(expected).stream() + .map(JavaSourceNames::simpleName) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + Set addedInterfaces = difference(expectedInterfaces, originalInterfaces); + assertTrue( + actual.interfaces().containsAll(addedInterfaces), + () -> + "Missing interfaces " + + difference(addedInterfaces, actual.interfaces()) + + " on " + + context); + + if (expected instanceof ASTCDEnum expectedEnum) { + List originalConstants = + original instanceof ASTCDEnum originalEnum + ? originalEnum.getCDEnumConstantList().stream() + .map(constant -> constant.getName()) + .toList() + : List.of(); + List constants = + expectedEnum.getCDEnumConstantList().stream().map(constant -> constant.getName()).toList(); + if (!constants.equals(originalConstants)) { + assertEquals(constants, actual.enumConstants(), "Wrong completed enum constants for " + context); + } + } + } + + private static Map fields(ASTCDType type) { + Map result = new LinkedHashMap<>(); + if (type != null) { + type.getCDAttributeList() + .forEach( + field -> + result.put(field.getName(), JavaSourceNames.printNormalizedFieldType(field))); + } + return result; + } + + private static Map methods(ASTCDType type) { + Map result = new LinkedHashMap<>(); + if (type != null) { + type.getCDMethodList() + .forEach( + method -> + result.put( + JavaSourceNames.methodSignature(method), + JavaSourceNames.printNormalizedReturnType(method))); + } + return result; + } + + private static Set interfaces(ASTCDType type) { + if (type == null) { + return Set.of(); + } + return CDTypeRelations.interfaceNames(type).stream() + .map(JavaSourceNames::simpleName) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + } + + private static String kind(ASTCDType type) { + if (type instanceof de.monticore.cdbasis._ast.ASTCDClass) { + return "class"; + } + if (type instanceof de.monticore.cdinterfaceandenum._ast.ASTCDInterface) { + return "interface"; + } + return "enum"; + } + + private static Set difference(Set expected, Set actual) { + Set missing = new LinkedHashSet<>(expected); + missing.removeAll(actual); + return missing; + } + + private static JavaAstElemCollector collect(ASTOrdinaryCompilationUnit unit) { + JavaAstElemCollector collector = new JavaAstElemCollector(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(collector); + unit.accept(traverser); + return collector; + } + + private record GeneratedType( + String kind, + Map fields, + Map methods, + String superclass, + Set interfaces, + List enumConstants, + Path source) { + + private static GeneratedType from( + ASTTypeDeclaration type, JavaAstElemCollector collector, Path source) { + Map fields = new LinkedHashMap<>(); + collector + .getAllFieldDeclarations(type) + .forEach( + field -> + field + .getVariableDeclaratorList() + .forEach( + variable -> + fields.put( + variable.getDeclarator().getName(), + JavaSourceNames.printNormalizedType(field.getMCType())))); + + Map methods = new LinkedHashMap<>(); + for (ASTMethodDeclaration method : collector.getAllMethodDeclarations(type)) { + List parameterTypes = + collector.getAllParameters(type, method).stream() + .map(parameter -> JavaSourceNames.printNormalizedType(parameter.getMCType())) + .toList(); + methods.put( + method.getName() + "(" + String.join(",", parameterTypes) + ")", + JavaSourceNames.normalizeType(JavaLoader.print(method.getMCReturnType()))); + } + + String kind; + String superclass = null; + Set interfaces = new LinkedHashSet<>(); + List enumConstants = List.of(); + if (type instanceof ASTClassDeclaration classDeclaration) { + kind = "class"; + if (classDeclaration.isPresentSuperClass()) { + superclass = JavaSourceNames.simpleName(JavaLoader.print(classDeclaration.getSuperClass())); + } + classDeclaration.getImplementedInterfaceList().stream() + .map(JavaLoader::print) + .map(JavaSourceNames::simpleName) + .forEach(interfaces::add); + } else if (type instanceof ASTInterfaceDeclaration interfaceDeclaration) { + kind = "interface"; + interfaceDeclaration.getExtendedInterfaceList().stream() + .map(JavaLoader::print) + .map(JavaSourceNames::simpleName) + .forEach(interfaces::add); + } else if (type instanceof ASTEnumDeclaration enumDeclaration) { + kind = "enum"; + enumDeclaration.getImplementedInterfaceList().stream() + .map(JavaLoader::print) + .map(JavaSourceNames::simpleName) + .forEach(interfaces::add); + List constants = new ArrayList<>(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL( + new JavaDSLVisitor2() { + @Override + public void visit(ASTEnumConstantDeclaration constant) { + constants.add(constant.getName()); + } + }); + enumDeclaration.accept(traverser); + enumConstants = List.copyOf(constants); + } else { + assertFalse(true, "Unsupported generated Java type " + type.getClass().getName()); + throw new AssertionError(); + } + return new GeneratedType( + kind, + Map.copyOf(fields), + Map.copyOf(methods), + superclass, + Set.copyOf(interfaces), + enumConstants, + source); + } + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/updater/CodeUpdaterMillTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/updater/CodeUpdaterMillTest.java new file mode 100644 index 00000000..9c302497 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/updater/CodeUpdaterMillTest.java @@ -0,0 +1,53 @@ +package de.monticore.codeAdaption.updater; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; + +import de.monticore.codeAdaption.updater.spoonUpdater.SpoonUpdater; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class CodeUpdaterMillTest { + + @AfterEach + void restoreDefaultProvider() { + CodeUpdaterMill.init(); + } + + @Test + void reusesCurrentUpdaterUntilReset() { + AtomicInteger createdUpdaters = new AtomicInteger(); + CodeUpdaterMill.init( + () -> { + createdUpdaters.incrementAndGet(); + return new SpoonUpdater(); + }); + + CodeUpdater first = CodeUpdaterMill.getUpdater(); + + assertSame(first, CodeUpdaterMill.getUpdater()); + assertEquals(1, createdUpdaters.get()); + + CodeUpdaterMill.reset(); + CodeUpdater second = CodeUpdaterMill.getUpdater(); + + assertNotSame(first, second); + assertEquals(2, createdUpdaters.get()); + } + + @Test + void initRestoresDefaultSpoonProviderAndClearsCurrentUpdater() { + CodeUpdater customUpdater = new SpoonUpdater(); + CodeUpdaterMill.init(() -> customUpdater); + assertSame(customUpdater, CodeUpdaterMill.getUpdater()); + + CodeUpdaterMill.init(); + CodeUpdater defaultUpdater = CodeUpdaterMill.getUpdater(); + + assertInstanceOf(SpoonUpdater.class, defaultUpdater); + assertNotSame(customUpdater, defaultUpdater); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonServicesTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonServicesTest.java new file mode 100644 index 00000000..a17bad86 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonServicesTest.java @@ -0,0 +1,845 @@ +package de.monticore.codeAdaption.updater.spoonUpdater; + +import de.monticore.codeAdaption.updater.CodeUpdater.MethodBodySpec; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.handler.multiIncarnation.StableElementKey; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import spoon.reflect.reference.CtTypeReference; + +class SpoonServicesTest { + @TempDir Path temporaryDirectory; + + @BeforeEach + void initializeMill() { + AdapterAbstractTest.initMills(); + } + + @Test + void reloadReplacesTheModelAndTypeReferencesAreClonedFromCachedPrototypes() throws IOException { + Path first = sourceDirectory("first", "First"); + Path second = sourceDirectory("second", "Second"); + SpoonWorkspace workspace = new SpoonWorkspace(); + + workspace.load(first); + assertEquals("First", workspace.model().getAllTypes().iterator().next().getSimpleName()); + CtTypeReference firstReference = workspace.createTypeReference("List"); + CtTypeReference secondReference = workspace.createTypeReference("List"); + assertNotSame(firstReference, secondReference); + + workspace.load(second); + assertEquals("Second", workspace.model().getAllTypes().iterator().next().getSimpleName()); + } + + @Test + void executableRewriteRegistryNormalizesSignaturesAndValidatesMethodKeys() { + ExecutableRewriteRegistry registry = new ExecutableRewriteRegistry(); + registry.registerConcreteSignature("run", List.of("java.lang.String", "any[]")); + + assertEquals(List.of("String", "Object[]"), registry.unambiguousLegacyParameters("run")); + assertThrows( + IllegalArgumentException.class, + () -> + registry.registerRewrite( + StableElementKey.type("NotAMethod"), + StableElementKey.method("Owner", "run", List.of()))); + } + + @Test + void typeResolutionUsesTheSourcePathWhenPackagesContainTheSameSimpleName() + throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("packages")); + Path first = javaSource(sources, "alpha", "Shared", "class Shared {}"); + javaSource(sources, "beta", "Shared", "class Shared {}"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + + ASTTypeDeclaration sourceType = loadType(first, "Shared"); + + assertEquals("alpha.Shared", resolver.getSpoonType(sourceType).getQualifiedName()); + } + + @Test + void methodResolutionRequiresAnExactDeclaredName() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("methods")); + Path source = + javaSource( + sources, + "sample", + "Child", + "class Base { void run() {} } class Child extends Base { void targetRun() {} }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + ASTTypeDeclaration child = loadType(source, "Child"); + ASTMethodDeclaration targetRun = loadMethod(source, "Child", "targetRun"); + + assertEquals("targetRun", resolver.getSpoonMethod(child, targetRun).getSimpleName()); + } + + @Test + void clonedMethodParametersRemainBoundToTheClonedBody() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("generation")); + Path source = + javaSource( + sources, + "sample", + "Echo", + "class Echo { String echo(String value) { return value; } " + + "String combine(String kept, String removed) { return kept + removed; } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonGenerationService generation = new SpoonGenerationService(workspace, resolver); + ASTTypeDeclaration echo = loadType(source, "Echo"); + ASTMethodDeclaration template = loadMethod(source, "Echo", "echo"); + + generation.addMethod( + echo, + template, + "renamedEcho", + List.of("String"), + List.of("renamedValue"), + "String", + false, + MethodBodySpec.empty()); + + String generated = + resolver.getSpoonType(echo).getMethodsByName("renamedEcho").get(0).toString(); + assertTrue(generated.contains("return renamedValue"), generated); + + generation.addMethod( + echo, + loadMethod(source, "Echo", "combine"), + "reduced", + List.of("String"), + List.of("kept"), + "String", + false, + MethodBodySpec.safeDefault()); + generation.addMethod( + echo, + template, + "expanded", + List.of("String", "int"), + List.of("value", "ignored"), + "String", + false, + MethodBodySpec.empty()); + + String reduced = resolver.getSpoonType(echo).getMethodsByName("reduced").get(0).toString(); + String expanded = resolver.getSpoonType(echo).getMethodsByName("expanded").get(0).toString(); + assertTrue(reduced.contains("return null"), reduced); + assertFalse(reduced.contains("removed"), reduced); + assertTrue(expanded.contains("return value"), expanded); + } + + @Test + void clonedPrimitiveMethodReplacesNullWithACompilableDefault() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("primitive-return")); + Path source = + javaSource( + sources, + "sample", + "Template", + "class Template { Object value() { return null; } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonGenerationService generation = new SpoonGenerationService(workspace, resolver); + ASTTypeDeclaration type = loadType(source, "Template"); + ASTMethodDeclaration template = loadMethod(source, "Template", "value"); + + generation.addMethod( + type, + template, + "number", + List.of(), + List.of(), + "int", + false, + MethodBodySpec.empty()); + + String generated = resolver.getSpoonType(type).getMethodsByName("number").get(0).toString(); + assertTrue(generated.contains("return 0"), generated); + } + + @Test + void completedModelProjectionCreatesAndRepairsDeclarationsWithoutTemplates() + throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("completion-delta")); + Path source = + javaSource( + sources, + "sample", + "Child", + "class Parent {} interface Contract {} enum Colour { RED, BLUE } " + + "class Child { Object value; }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonGenerationService generation = new SpoonGenerationService(workspace, resolver); + ASTTypeDeclaration child = loadType(source, "Child"); + ASTTypeDeclaration colour = loadType(source, "Colour"); + + generation.addField(child, null, "value", "int", false); + generation.addField(child, null, "added", "String", false); + generation.addMethod( + child, + null, + "number", + List.of(), + List.of(), + "int", + false, + MethodBodySpec.empty()); + generation.addSuperType(child, "Parent", false); + generation.addSuperType(child, "Contract", true); + generation.addEnumConstant(colour, "GREEN", 1); + + var spoonChild = resolver.getSpoonType(child); + assertEquals("int", spoonChild.getField("value").getType().getSimpleName()); + assertEquals("String", spoonChild.getField("added").getType().getSimpleName()); + assertTrue(spoonChild.getMethodsByName("number").get(0).toString().contains("return 0")); + assertEquals("Parent", spoonChild.getSuperclass().getSimpleName()); + assertTrue( + spoonChild.getSuperInterfaces().stream() + .anyMatch(type -> "Contract".equals(type.getSimpleName()))); + assertEquals( + List.of("RED", "GREEN", "BLUE"), + ((spoon.reflect.declaration.CtEnum) resolver.getSpoonType(colour)) + .getEnumValues().stream() + .map(value -> value.getSimpleName()) + .toList()); + } + + @Test + void concreteInterfaceContractsArePublicAndReceiveSafeBodies() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("interface-contracts")); + Path source = + javaSource( + sources, + "sample", + "Implementation", + "class Implementation { String existing() { return \"kept\"; } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonGenerationService generation = new SpoonGenerationService(workspace, resolver); + ASTTypeDeclaration implementation = loadType(source, "Implementation"); + + generation.setTypeAbstract(implementation, true); + assertTrue( + resolver + .getSpoonType(implementation) + .hasModifier(spoon.reflect.declaration.ModifierKind.ABSTRACT)); + generation.setTypeAbstract(implementation, false); + assertFalse( + resolver + .getSpoonType(implementation) + .hasModifier(spoon.reflect.declaration.ModifierKind.ABSTRACT)); + + generation.addMethod( + implementation, + null, + "existing", + List.of(), + List.of(), + "String", + false, + MethodBodySpec.interfaceContract()); + generation.addMethod( + implementation, + null, + "enabled", + List.of(), + List.of(), + "boolean", + false, + MethodBodySpec.interfaceContract()); + generation.addMethod( + implementation, + null, + "description", + List.of(), + List.of(), + "String", + false, + MethodBodySpec.interfaceContract()); + generation.addMethod( + implementation, + null, + "reset", + List.of(), + List.of(), + "void", + false, + MethodBodySpec.interfaceContract()); + + var type = resolver.getSpoonType(implementation); + String existing = type.getMethodsByName("existing").get(0).toString(); + assertTrue(existing.contains("public"), existing); + assertTrue(existing.contains("return \"kept\""), existing); + assertTrue(type.getMethodsByName("enabled").get(0).toString().contains("return false")); + assertTrue(type.getMethodsByName("description").get(0).toString().contains("return null")); + assertNotNull(type.getMethodsByName("reset").get(0).getBody()); + } + + @Test + void interfaceContractPreservesExistingCovariantReturnAndBody() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("covariant-contract")); + Path source = + javaSource( + sources, + "sample", + "Implementation", + "class Implementation { protected String value() { return \"kept\"; } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonGenerationService generation = new SpoonGenerationService(workspace, resolver); + ASTTypeDeclaration implementation = loadType(source, "Implementation"); + + generation.addMethod( + implementation, + null, + "value", + List.of(), + List.of(), + "Object", + false, + MethodBodySpec.interfaceContract()); + + var method = resolver.getSpoonType(implementation).getMethodsByName("value").get(0); + assertEquals("String", method.getType().getSimpleName()); + assertTrue(method.hasModifier(spoon.reflect.declaration.ModifierKind.PUBLIC)); + assertFalse(method.hasModifier(spoon.reflect.declaration.ModifierKind.PROTECTED)); + assertTrue(method.toString().contains("return \"kept\""), method.toString()); + } + + @Test + void interfaceContractRejectsIncompatibleOrStaticExistingMethod() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("invalid-contract")); + Path source = + javaSource( + sources, + "sample", + "Implementation", + "class Implementation { Integer value() { return 1; } " + + "static String utility() { return \"kept\"; } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonGenerationService generation = new SpoonGenerationService(workspace, resolver); + ASTTypeDeclaration implementation = loadType(source, "Implementation"); + + assertThrows( + IllegalStateException.class, + () -> + generation.addMethod( + implementation, + null, + "value", + List.of(), + List.of(), + "String", + false, + MethodBodySpec.interfaceContract())); + assertThrows( + IllegalStateException.class, + () -> + generation.addMethod( + implementation, + null, + "utility", + List.of(), + List.of(), + "String", + false, + MethodBodySpec.interfaceContract())); + + assertEquals( + "Integer", + resolver + .getSpoonType(implementation) + .getMethodsByName("value") + .get(0) + .getType() + .getSimpleName()); + assertTrue( + resolver + .getSpoonType(implementation) + .getMethodsByName("utility") + .get(0) + .hasModifier(spoon.reflect.declaration.ModifierKind.STATIC)); + } + + @Test + void interfaceContractUsesPreservedReturnForSynthesizedBody() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("bodyless-contract")); + Path source = + javaSource( + sources, + "sample", + "Implementation", + "abstract class Implementation { protected abstract String value(); }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonGenerationService generation = new SpoonGenerationService(workspace, resolver); + ASTTypeDeclaration implementation = loadType(source, "Implementation"); + + generation.addMethod( + implementation, + null, + "value", + List.of(), + List.of(), + "Object", + false, + MethodBodySpec.interfaceContract()); + + var method = resolver.getSpoonType(implementation).getMethodsByName("value").get(0); + assertEquals("String", method.getType().getSimpleName()); + assertFalse(method.hasModifier(spoon.reflect.declaration.ModifierKind.ABSTRACT)); + assertTrue(method.toString().contains("return null"), method.toString()); + } + + @Test + void interfaceContractKeepsACompatibleInheritedImplementation() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("inherited-contract")); + Path source = + javaSource( + sources, + "sample", + "Child", + "class Base { public String value() { return \"base\"; } } class Child extends Base {}"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonGenerationService generation = new SpoonGenerationService(workspace, resolver); + ASTTypeDeclaration childAst = loadType(source, "Child"); + + generation.addMethod( + childAst, + null, + "value", + List.of(), + List.of(), + "Object", + false, + MethodBodySpec.interfaceContract()); + + var child = resolver.getSpoonType(childAst); + var base = workspace.model().getAllTypes().stream() + .filter(type -> "Base".equals(type.getSimpleName())) + .findFirst() + .orElseThrow(); + assertTrue(child.getMethods().stream().noneMatch(method -> "value".equals(method.getSimpleName()))); + assertTrue(base.getMethodsByName("value").get(0).toString().contains("return \"base\"")); + } + + @Test + void generatedMethodLookupDistinguishesQualifiedParameterTypes() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("qualified-overload")); + javaSource(sources, "alpha", "Value", "public class Value {}"); + javaSource(sources, "beta", "Value", "public class Value {}"); + Path source = + javaSource( + sources, + "sample", + "Service", + "class Service { void run(alpha.Value value) {} }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonGenerationService generation = new SpoonGenerationService(workspace, resolver); + ASTTypeDeclaration service = loadType(source, "Service"); + + generation.addMethod( + service, + null, + "run", + List.of("beta.Value"), + List.of("value"), + "void", + false, + MethodBodySpec.empty()); + + assertEquals(2, resolver.getSpoonType(service).getMethodsByName("run").size()); + } + + @Test + void typeRewriteDoesNotTouchResolvedLibraryTypesWithTheSameSimpleName() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("library-type")); + javaSource( + sources, + "sample", + "UsesDate", + "class UsesDate { java.util.Date createdAt; }"); + Path cd = temporaryDirectory.resolve("Model.cd"); + Files.writeString(cd, "classdiagram Model { class Date; }"); + ASTCDType date = + JavaLoader.parseCD(cd.toString()).getCDDefinition().getCDClassesList().get(0); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonTransformationService transformations = services(workspace).transformations(); + + transformations.updateCDType(date, "RenamedDate"); + + var renderedType = workspace.model().getAllTypes().iterator().next(); + assertEquals( + "java.util.Date", + renderedType.getField("createdAt").getType().getQualifiedName()); + } + + @Test + void typeRewriteUpdatesUnresolvedTypesFromTheAdapterPackage() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("adapter-type")); + javaSource( + sources, + "sample", + "UsesRole", + "class UsesRole { Role role; Role first(Role fallback) { return fallback; } }"); + Path cd = temporaryDirectory.resolve("Reference.cd"); + Files.writeString(cd, "classdiagram Reference { class Role; }"); + ASTCDType role = + JavaLoader.parseCD(cd.toString()).getCDDefinition().getCDClassesList().get(0); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + SpoonTransformationService transformations = services(workspace).transformations(); + + transformations.updateCDType(role, "HiwiRole"); + + CtTypeReference fieldType = + workspace.model().getAllTypes().iterator().next().getField("role").getType(); + assertEquals("HiwiRole", fieldType.getSimpleName()); + assertTrue( + workspace.model().getAllTypes().iterator().next().toString().contains("HiwiRole first")); + } + + @Test + void methodRenameUpdatesOnlyTheSelectedOverload() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("overload-rename")); + Path source = + javaSource( + sources, + "sample", + "Service", + "class Service { void run(String value) {} void run(int first, int second) {} " + + "void call() { run(\"x\"); run(1, 2); } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + Services services = services(workspace); + + services + .transformations() + .updateMethod(loadType(source, "Service"), loadMethod(source, "Service", "run", 1), "execute"); + + String rendered = workspace.model().getAllTypes().stream() + .filter(type -> "Service".equals(type.getSimpleName())) + .findFirst() + .orElseThrow() + .toString(); + assertTrue(rendered.contains("execute(\"x\")"), rendered); + assertTrue(rendered.contains("run(1, 2)"), rendered); + assertEquals(1, workspace.model().getAllTypes().iterator().next().getMethodsByName("run").size()); + } + + @Test + void methodRenameUpdatesStaticAndInheritedInvocations() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("static-inherited")); + Path source = + javaSource( + sources, + "sample", + "Base", + "class Base { static void create() {} void run() {} } " + + "class Child extends Base { void call() { run(); Base.create(); } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + Services services = services(workspace); + ASTTypeDeclaration base = loadType(source, "Base"); + + services.transformations().updateMethod(base, loadMethod(source, "Base", "run"), "execute"); + services.transformations().updateMethod(base, loadMethod(source, "Base", "create"), "make"); + + String rendered = workspace.model().getAllTypes().stream() + .filter(type -> "Child".equals(type.getSimpleName())) + .findFirst() + .orElseThrow() + .toString(); + assertTrue(rendered.contains("execute()"), rendered); + assertTrue(rendered.contains("Base.make()"), rendered); + } + + @Test + void stableMethodRewriteSelectsTheOverloadAndAddsACompatibleArgument() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("signature-repair")); + javaSource( + sources, + "sample", + "Service", + "class Item {} class SpecialItem extends Item {} class OtherItem extends Item {} " + + "class Service { void target(String value) {} void target(int value) {} " + + "void call(SpecialItem special) { target(\"x\"); target(1); } " + + "void exact(Item item, SpecialItem special) { target(\"y\"); } " + + "void ambiguous(SpecialItem first, OtherItem second) { target(\"z\"); } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + Services services = services(workspace); + services + .repairs() + .registerMethodRewrite( + StableElementKey.method("Service", "target", List.of("String")), + StableElementKey.method("Service", "execute", List.of("String", "Item"))); + + services.repairs().prepareForPrint(Map.of()); + + String rendered = workspace.model().getAllTypes().stream() + .filter(type -> "Service".equals(type.getSimpleName())) + .findFirst() + .orElseThrow() + .toString(); + assertTrue(rendered.contains("execute(\"x\", special)"), rendered); + assertTrue(rendered.contains("execute(\"y\", item)"), rendered); + assertTrue(rendered.contains("execute(\"z\", null)"), rendered); + assertTrue(rendered.contains("target(1)"), rendered); + } + + @Test + void missingArgumentRejectsDifferentlyQualifiedTypeWithSameSimpleName() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("ambiguous-argument")); + javaSource(sources, "alpha", "Role", "public class Role {}"); + javaSource(sources, "beta", "Role", "public class Role {}"); + javaSource( + sources, + "sample", + "Service", + "class Service { void targetRole(String value) {} " + + "void qualified(alpha.Role role) { targetRole(\"y\"); } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + Services services = services(workspace); + services + .repairs() + .registerMethodRewrite( + StableElementKey.method("Service", "targetRole", List.of("String")), + StableElementKey.method("Service", "executeRole", List.of("String", "beta.Role"))); + + services.repairs().prepareForPrint(Map.of()); + + String rendered = workspace.model().getAllTypes().stream() + .filter(type -> "Service".equals(type.getSimpleName())) + .findFirst() + .orElseThrow() + .toString(); + assertTrue(rendered.contains("executeRole(\"y\", null)"), rendered); + } + + @Test + void missingArgumentReusesUniqueImportedParametersForUnqualifiedStableTypes() + throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("imported-argument")); + javaSource( + sources, + "sample", + "Service", + "import java.util.Date; import java.util.List; " + + "class Service { void target(String value) {} " + + "void imported(Date date, List values) { target(\"x\"); } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + Services services = services(workspace); + services + .repairs() + .registerMethodRewrite( + StableElementKey.method("Service", "target", List.of("String")), + StableElementKey.method( + "Service", "execute", List.of("String", "Date", "List"))); + + services.repairs().prepareForPrint(Map.of()); + + String rendered = workspace.model().getAllTypes().stream() + .filter(type -> "Service".equals(type.getSimpleName())) + .findFirst() + .orElseThrow() + .toString(); + assertTrue(rendered.contains("execute(\"x\", date, values)"), rendered); + } + + @Test + void groupingRunsBeforeOwnerAwareExecutableRepair() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("grouped-owner")); + javaSource( + sources, + "sample", + "ConcreteService", + "class ConcreteService { void target(String value) {} } " + + "class Caller { ConcreteService service; " + + "void call(String suffix) { service.target(\"x\"); } }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + Services services = services(workspace); + services.transformations().setGroupingMappings(Map.of("ConcreteService", "ServiceGroup")); + services + .repairs() + .registerMethodRewrite( + StableElementKey.method("ReferenceService", "target", List.of("String")), + StableElementKey.method( + "ConcreteService", "execute", List.of("String", "String"))); + + services.transformations().prepareForPrint(); + + String caller = workspace.model().getAllTypes().stream() + .filter(type -> "Caller".equals(type.getSimpleName())) + .findFirst() + .orElseThrow() + .toString(); + assertTrue(caller.contains("ServiceGroup service"), caller); + assertTrue(caller.contains("service.execute(\"x\", suffix)"), caller); + } + + @Test + void constructorCallsFollowTypeReferenceRewrites() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("constructor-type")); + javaSource( + sources, + "sample", + "Factory", + "class Factory { Role create() { return new Role(); } }"); + Path cd = temporaryDirectory.resolve("ConstructorReference.cd"); + Files.writeString(cd, "classdiagram Reference { class Role; }"); + ASTCDType role = JavaLoader.parseCD(cd.toString()).getCDDefinition().getCDClassesList().get(0); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + Services services = services(workspace); + + services.transformations().updateCDType(role, "HiwiRole"); + + String rendered = workspace.model().getAllTypes().iterator().next().toString(); + assertTrue(rendered.contains("HiwiRole create()"), rendered); + assertTrue(rendered.contains("new HiwiRole()"), rendered); + } + + @Test + void executablePreparationRemovesOnlyIllegalInterfaceBodies() throws IOException { + Path sources = Files.createDirectory(temporaryDirectory.resolve("interface-methods")); + javaSource( + sources, + "sample", + "Contract", + "interface Contract { void run(); default void keep() {} static void utility() {} }"); + SpoonWorkspace workspace = new SpoonWorkspace(); + workspace.load(sources); + Services services = services(workspace); + var contract = workspace.model().getAllTypes().iterator().next(); + contract.getMethodsByName("run").get(0).setBody(workspace.factory().createBlock()); + + services.repairs().prepareForPrint(Map.of()); + + assertNull(contract.getMethodsByName("run").get(0).getBody()); + assertNotNull(contract.getMethodsByName("keep").get(0).getBody()); + assertNotNull(contract.getMethodsByName("utility").get(0).getBody()); + } + + private Path sourceDirectory(String directoryName, String typeName) throws IOException { + Path directory = Files.createDirectory(temporaryDirectory.resolve(directoryName)); + Files.writeString( + directory.resolve(typeName + ".java"), + "class " + typeName + " {}", + StandardCharsets.UTF_8); + return directory; + } + + private Path javaSource( + Path sourceRoot, String packageName, String typeName, String declaration) throws IOException { + Path directory = Files.createDirectories(sourceRoot.resolve(packageName.replace('.', '/'))); + Path source = directory.resolve(typeName + ".java"); + Files.writeString( + source, + "package " + packageName + "; " + declaration, + StandardCharsets.UTF_8); + return source; + } + + private ASTTypeDeclaration loadType(Path source, String typeName) { + JavaAstElemCollector collector = collect(source); + return collector.getAllTypeDeclarations().stream() + .filter(type -> typeName.equals(type.getName())) + .findFirst() + .orElseThrow(); + } + + private ASTMethodDeclaration loadMethod(Path source, String typeName, String methodName) { + JavaAstElemCollector collector = collect(source); + ASTTypeDeclaration type = + collector.getAllTypeDeclarations().stream() + .filter(candidate -> typeName.equals(candidate.getName())) + .findFirst() + .orElseThrow(); + return collector.getAllMethodDeclarations(type).stream() + .filter(method -> methodName.equals(method.getName())) + .findFirst() + .orElseThrow(); + } + + private ASTMethodDeclaration loadMethod( + Path source, String typeName, String methodName, int parameterCount) { + JavaAstElemCollector collector = collect(source); + ASTTypeDeclaration type = + collector.getAllTypeDeclarations().stream() + .filter(candidate -> typeName.equals(candidate.getName())) + .findFirst() + .orElseThrow(); + return collector.getAllMethodDeclarations(type).stream() + .filter(method -> methodName.equals(method.getName())) + .filter(method -> collector.getAllParameters(type, method).size() == parameterCount) + .findFirst() + .orElseThrow(); + } + + private Services services(SpoonWorkspace workspace) { + SpoonElementResolver resolver = new SpoonElementResolver(workspace::model); + SpoonExecutableRepairService repairs = new SpoonExecutableRepairService(workspace, resolver); + return new Services( + repairs, new SpoonTransformationService(workspace, resolver, repairs)); + } + + private record Services( + SpoonExecutableRepairService repairs, SpoonTransformationService transformations) {} + + private JavaAstElemCollector collect(Path source) { + ASTOrdinaryCompilationUnit ast = JavaLoader.loadJava(source.toFile()); + JavaAstElemCollector collector = new JavaAstElemCollector(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(collector); + ast.accept(traverser); + return collector; + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/AdaptReferenceTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/AdaptReferenceTest.java new file mode 100644 index 00000000..eacfafb4 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/AdaptReferenceTest.java @@ -0,0 +1,66 @@ +package de.monticore.codeAdaption.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.java.javadsl.JavaDSLMill; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class AdaptReferenceTest { + + @BeforeEach + void setUp() { + JavaDSLMill.init(); + JavaDSLMill.globalScope().clear(); + LogStub.init(); + LogStub.enableFailQuick(false); + } + + @Test + void parsesQualifiedOwnerWithoutConfusingParameterTypePackages() { + AdaptReference reference = + AdaptReference.parse("model.Order.update(java.time.Instant)").orElseThrow(); + + assertEquals("model.Order", reference.owner().orElseThrow()); + assertEquals("update", reference.memberName()); + assertEquals("update(Instant)", reference.methodSignature().orElseThrow()); + } + + @Test + void normalizesNestedGenericMethodParametersThroughJavaDsl() { + AdaptReference reference = + AdaptReference.parse("Outer.Inner.update(Map>)").orElseThrow(); + + assertEquals("Outer.Inner", reference.owner().orElseThrow()); + assertEquals("update(Map>)", reference.memberReference()); + } + + @Test + void distinguishesFieldsAndMethods() { + AdaptReference field = AdaptReference.parse("model.Order.number").orElseThrow(); + AdaptReference method = AdaptReference.parse("update()").orElseThrow(); + + assertFalse(field.isMethod()); + assertEquals("number", field.memberName()); + assertTrue(method.isMethod()); + assertTrue(method.owner().isEmpty()); + } + + @Test + void rejectsMalformedReferences() { + assertTrue(AdaptReference.parse("malformed(reference").isEmpty()); + assertTrue(AdaptReference.parse(".field").isEmpty()); + assertTrue(AdaptReference.parse("Owner.").isEmpty()); + } + + @Test + void annotationNamesRequireAnExactMatch() { + assertTrue(AdaptAnnotationNames.matches("Adapt")); + assertTrue(AdaptAnnotationNames.matches("de.monticore.codeAdaption.utils.Adapt")); + assertFalse(AdaptAnnotationNames.matches("NotAdapt")); + assertFalse(AdaptAnnotationNames.matches("example.NotAdapt")); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/CDImportProjectorTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/CDImportProjectorTest.java new file mode 100644 index 00000000..0ac97d25 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/CDImportProjectorTest.java @@ -0,0 +1,131 @@ +package de.monticore.codeAdaption.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class CDImportProjectorTest extends AdapterAbstractTest { + + @TempDir Path tempDir; + + @BeforeEach + void setUp() { + initMills(); + } + + @Test + void projectsOnlyExplicitImportsUsedByTheJavaUnit() throws IOException { + ASTCDCompilationUnit reference = + cd( + "Reference", + """ + import alpha.types.Widget; + import alpha.time.Date; + """); + ASTCDCompilationUnit concrete = + cd( + "Concrete", + """ + import beta.time.Date; + import beta.types.Unused; + """); + ASTOrdinaryCompilationUnit unit = java("Holder", "class Holder { Widget value; }"); + + CDImportProjector.project(Set.of(unit), reference, concrete); + + assertEquals(List.of("alpha.types.Widget"), imports(unit)); + } + + @Test + void preservesAnExistingJavaBindingOnCdCollision() throws IOException { + ASTCDCompilationUnit reference = cd("Reference", "import org.joda.time.Date;"); + ASTOrdinaryCompilationUnit unit = + java( + "Holder", + """ + import java.util.Date; + class Holder { Date value; } + """); + + CDImportProjector.project(Set.of(unit), reference); + + assertEquals(List.of("java.util.Date"), imports(unit)); + } + + @Test + void rejectsUsedReferenceConcreteImportCollisionDeterministically() throws IOException { + ASTCDCompilationUnit reference = cd("Reference", "import z.reference.Date;"); + ASTCDCompilationUnit concrete = cd("Concrete", "import a.concrete.Date;"); + ASTOrdinaryCompilationUnit unit = java("Holder", "class Holder { Date value; }"); + + IllegalStateException exception = + assertThrows( + IllegalStateException.class, + () -> CDImportProjector.project(Set.of(unit), reference, concrete)); + + assertTrue(exception.getMessage().contains("a.concrete.Date, z.reference.Date")); + assertEquals(List.of(), imports(unit)); + } + + @Test + void deduplicatesTheSameExplicitImportAcrossJavaAndCds() throws IOException { + ASTCDCompilationUnit reference = cd("Reference", "import java.util.List;"); + ASTCDCompilationUnit concrete = cd("Concrete", "import java.util.List;"); + ASTOrdinaryCompilationUnit unit = + java( + "Holder", + """ + import java.util.List; + class Holder { List values; } + """); + + CDImportProjector.project(Set.of(unit), reference, concrete); + + assertEquals(List.of("java.util.List"), imports(unit)); + } + + @Test + void preservesAndDeduplicatesCdWildcardImports() throws IOException { + ASTCDCompilationUnit reference = cd("Reference", "import java.util.*;"); + ASTCDCompilationUnit concrete = cd("Concrete", "import java.util.*;"); + ASTOrdinaryCompilationUnit unit = java("Holder", "class Holder {}"); + + CDImportProjector.project(Set.of(unit), reference, concrete); + + assertEquals(List.of("java.util.*"), imports(unit)); + assertTrue(unit.getImportDeclarationList().get(0).isSTAR()); + } + + private ASTCDCompilationUnit cd(String name, String imports) throws IOException { + Path file = tempDir.resolve(name + ".cd"); + Files.writeString(file, imports + System.lineSeparator() + "classdiagram " + name + " {}"); + return JavaLoader.parseCD(file.toString()); + } + + private ASTOrdinaryCompilationUnit java(String name, String source) throws IOException { + Path file = tempDir.resolve(name + ".java"); + Files.writeString(file, source); + return JavaLoader.loadJava(file.toFile()); + } + + private static List imports(ASTOrdinaryCompilationUnit unit) { + return unit.getImportDeclarationList().stream() + .map( + importDeclaration -> + importDeclaration.getMCQualifiedName().getQName() + + (importDeclaration.isSTAR() ? ".*" : "")) + .toList(); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaAstElemCollectorTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaAstElemCollectorTest.java index 64590171..5003eddc 100644 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaAstElemCollectorTest.java +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaAstElemCollectorTest.java @@ -34,7 +34,7 @@ public void testTypeOperationCollection() { ast.accept(traverser); // check a type collection - Assertions.assertEquals(collector.getAllTypeDeclarations().size(), 1); + Assertions.assertEquals(1, collector.getAllTypeDeclarations().size()); // check type element collection ASTTypeDeclaration t = collector.getAllTypeDeclarations().get(0); diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaSourceNamesTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaSourceNamesTest.java new file mode 100644 index 00000000..43cef09c --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaSourceNamesTest.java @@ -0,0 +1,91 @@ +package de.monticore.codeAdaption.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import de.se_rwth.commons.logging.LogStub; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class JavaSourceNamesTest { + + @BeforeEach + void setUp() { + LogStub.init(); + LogStub.enableFailQuick(false); + } + + @Test + void normalizesQualifiedGenericArrayAndAnyTypes() { + assertEquals( + "Map>", + JavaSourceNames.normalizeType("java.util.Map>")); + assertEquals("Object", JavaSourceNames.normalizeType("any")); + assertEquals("String[]", JavaSourceNames.normalizeType("java.lang.String []")); + assertEquals("int[]", JavaSourceNames.normalizeType("int[]")); + assertEquals("void", JavaSourceNames.normalizeType("void")); + assertEquals("Optional", JavaSourceNames.normalizeType("Optional")); + assertEquals("List", JavaSourceNames.normalizeType("List")); + assertEquals( + "List", + JavaSourceNames.normalizeType("java.util.List")); + } + + @Test + void replacesSimpleTypeNamesInsideNestedGenericTypes() { + String replaced = + JavaSourceNames.replaceSimpleTypeNames( + "Map>", + simple -> "Person".equals(simple) ? Optional.of("Named") : Optional.empty()); + + assertEquals("Map>", replaced); + } + + @Test + void preservesQualifiedNamesWhenReplacingParsedTypeLeaves() { + String replaced = + JavaSourceNames.replaceSimpleTypeNames( + "java.util.Map>", + simple -> "Person".equals(simple) ? Optional.of("Named") : Optional.empty()); + + assertEquals("java.util.Map>", replaced); + } + + @Test + void extractsQualifiedIdentityFromNestedGenericAndWildcardTypes() { + assertEquals( + List.of( + new JavaSourceNames.TypeReferenceName("java.util.Map", "Map", true), + new JavaSourceNames.TypeReferenceName("a.User", "User", true), + new JavaSourceNames.TypeReferenceName("java.util.List", "List", true), + new JavaSourceNames.TypeReferenceName("b.User", "User", true)), + JavaSourceNames.typeReferences( + "java.util.Map>")); + } + + @Test + void extractsSimpleNameThroughTypeParserWhenPossible() { + assertEquals("Entry", JavaSourceNames.simpleName("java.util.Map.Entry")); + assertEquals("List", JavaSourceNames.simpleName("java.util.List[]")); + assertEquals("update", JavaSourceNames.simpleName("update()")); + } + + @Test + void normalizesMethodParametersThroughTheTypeParser() { + assertEquals( + Optional.of("update(Map>,int[],long)"), + JavaMethodSignatures.parseNormalized( + " update(java.util.Map>, int[], long) ")); + assertEquals(Optional.of("update()"), JavaMethodSignatures.parseNormalized(" update( ) ")); + } + + @Test + void rejectsMalformedMethodSignatures() { + assertEquals( + Optional.empty(), + JavaMethodSignatures.parseNormalized("update(Map,int)")); + assertEquals( + Optional.empty(), JavaMethodSignatures.parseNormalized("update(String) trailing")); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaSourcePostProcessorTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaSourcePostProcessorTest.java new file mode 100644 index 00000000..37075cd3 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaSourcePostProcessorTest.java @@ -0,0 +1,239 @@ +package de.monticore.codeAdaption.utils; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class JavaSourcePostProcessorTest { + + @TempDir Path tempDir; + + @Test + void preservesCommentsAndLiteralsWhileRemovingInvalidImports() { + String source = + """ + package demo; + import Person; + import de.monticore.codeAdaption.utils.Adapt; + import java.util.HashMap; + + public class Example { + String url = "http://example/a,b"; + String block = "/* not a comment */"; + java.util.Map map = new HashMap<>(); + + void m() { + int x=1; // keep comma,a and equals= + /* keep generic List text */ + } + } + """; + + String cleaned = JavaSourcePostProcessor.process(source); + + assertFalse(cleaned.contains("import Person;")); + assertFalse(cleaned.contains("import de.monticore.codeAdaption.utils.Adapt;")); + assertTrue(cleaned.contains("import java.util.HashMap;")); + assertTrue(cleaned.contains("\"http://example/a,b\"")); + assertTrue(cleaned.contains("int x=1; // keep comma,a and equals=")); + assertTrue(cleaned.contains("/* keep generic List text */")); + } + + @Test + void removesInvalidImportsAndPreservesExistingValidImportsWithoutAddingJdkImports() { + String source = + """ + package demo; + + // List in a comment must not drive imports by itself. + import de.monticore.codeAdaption.utils.Adapt; + import Person; + import static java.util.Collections.emptyList; + import java.io.File; + + public class Sample { + private List names; + private Map> ids; + private ZonedDateTime created; + private File file; + private String literal = "Set"; + } + """; + + String cleaned = JavaSourcePostProcessor.process(source, "Sample.java"); + + assertFalse(cleaned.contains("import de.monticore.codeAdaption.utils.Adapt;")); + assertFalse(cleaned.contains("import Person;")); + assertTrue(cleaned.contains("import static java.util.Collections.emptyList;")); + assertTrue(cleaned.contains("import java.io.File;")); + assertFalse(cleaned.contains("import java.util.List;")); + assertFalse(cleaned.contains("import java.util.Map;")); + assertFalse(cleaned.contains("import java.util.Optional;")); + assertFalse(cleaned.contains("import java.util.UUID;")); + assertFalse(cleaned.contains("import java.time.ZonedDateTime;")); + assertFalse(cleaned.contains("import java.util.Set;")); + } + + @Test + void preservesExistingJavaUtilWildcardWithoutAddingExplicitImports() { + String source = + """ + package demo; + + import java.util.*; + + public class Sample { + private List names; + } + """; + + String cleaned = JavaSourcePostProcessor.process(source, "Sample.java"); + + assertTrue(cleaned.contains("import java.util.*;")); + assertFalse(cleaned.contains("import java.util.List;")); + } + + @Test + void doesNotInventImportsForUnresolvedSimpleNames() { + String source = + """ + package demo; + + class List {} + + public class Sample { + private List names; + private Optional value; + } + """; + + String cleaned = JavaSourcePostProcessor.process(source, "Sample.java"); + + assertFalse(cleaned.contains("import java.util.List;")); + assertFalse(cleaned.contains("import java.util.Optional;")); + } + + @Test + void processDirectoryDoesNotInventImportsForSamePackageTypes() throws IOException { + Path list = tempDir.resolve("List.java"); + Path sample = tempDir.resolve("Sample.java"); + Files.writeString( + list, + """ + package demo; + + public class List {} + """, + StandardCharsets.UTF_8); + Files.writeString( + sample, + """ + package demo; + + public class Sample { + private List names; + private Map values; + } + """, + StandardCharsets.UTF_8); + + JavaSourcePostProcessor.processDirectory(tempDir); + String cleaned = Files.readString(sample, StandardCharsets.UTF_8); + + assertFalse(cleaned.contains("import java.util.List;")); + assertFalse(cleaned.contains("import java.util.Map;")); + } + + @Test + void removesOnlyMalformedParameterizedImportLines() { + String source = + """ + package demo; + + import Optional; + import static java.util.Collections.emptyList; + + public class Sample { + private Optional value; + private List numbers; + } + """; + + String cleaned = JavaSourcePostProcessor.process(source, "Sample.java"); + + assertFalse(cleaned.contains("import Optional;")); + assertTrue(cleaned.contains("import static java.util.Collections.emptyList;")); + assertFalse(cleaned.contains("import java.util.Optional;")); + assertFalse(cleaned.contains("import java.util.List;")); + assertTrue(cleaned.contains("Optional value")); + assertTrue(cleaned.contains("List numbers")); + } + + @Test + void malformedImportRecoveryPreservesCommentsAndTextBlocks() { + String source = + String.join( + System.lineSeparator(), + "package demo;", + "", + "/*", + " import Commented;", + "*/", + "import Optional;", + "", + "public class Sample {", + " String text = \"\"\"", + " import TextBlock;", + " \"\"\";", + " String literal = \"import Literal;\";", + "}", + ""); + + String cleaned = JavaSourcePostProcessor.process(source, "Sample.java"); + + assertFalse(cleaned.contains("import Optional;")); + assertTrue(cleaned.contains("import Commented;")); + assertTrue(cleaned.contains("import TextBlock;")); + assertTrue(cleaned.contains("\"import Literal;\"")); + } + + @Test + void printAstPreservesPackageDirectoriesForSameSimpleNames() throws IOException { + Path inputDir = tempDir.resolve("input"); + Path outputDir = tempDir.resolve("output"); + Files.createDirectories(inputDir.resolve("a")); + Files.createDirectories(inputDir.resolve("b")); + Files.writeString( + inputDir.resolve("a").resolve("User.java"), + """ + package a; + + public class User {} + """, + StandardCharsets.UTF_8); + Files.writeString( + inputDir.resolve("b").resolve("User.java"), + """ + package b; + + public class User {} + """, + StandardCharsets.UTF_8); + + Set asts = JavaLoader.readJavaCode(inputDir); + JavaLoader.printAST(asts, outputDir); + + assertTrue(Files.exists(outputDir.resolve("a").resolve("User.java"))); + assertTrue(Files.exists(outputDir.resolve("b").resolve("User.java"))); + assertFalse(Files.exists(outputDir.resolve("User.java"))); + } + +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/validator/CodeValidatorTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/validator/CodeValidatorTest.java index c390be48..3b0bee39 100644 --- a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/validator/CodeValidatorTest.java +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/validator/CodeValidatorTest.java @@ -9,15 +9,22 @@ import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; import de.se_rwth.commons.logging.Log; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Set; import java.util.stream.Stream; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; class CodeValidatorTest extends AdapterAbstractTest { + @TempDir Path tempDir; + protected String baseDir = "src/test/resources/de/monticore/codeAdaption/validator/"; protected CodeValidator validator; protected ASTCDCompilationUnit cd; @@ -41,31 +48,91 @@ public static Stream invalidFiles1() { Arguments.of("MissingTemplateArgument.java", "0xRC001")); } - public static Stream invalidFiles2() { - return Stream.of(Arguments.of("InvalidTemplate.java", "0xRC003")); - } - @ParameterizedTest @MethodSource("invalidFiles1") public void checkAnnotationPhase1(String filename, String errorCode) { String fileName = baseDir + "invalid/" + filename; ASTOrdinaryCompilationUnit ast = JavaLoader.loadJava(new File(fileName)); - validator.runCoCosPhase1(ast, cd); + validator.runAdapterCoCos(ast, cd); Assertions.assertEquals(1, Log.getErrorCount()); Assertions.assertTrue(Log.getFindings().get(0).getMsg().startsWith(errorCode)); } - @ParameterizedTest - @MethodSource("invalidFiles2") - public void checkAnnotationPhase2(String filename, String errorCode) { + @Test + void literalDollarDoesNotCountAsTemplatePlaceholder() throws IOException { + ASTOrdinaryCompilationUnit ast = + javaSource( + "LiteralDollar.java", + """ + import de.monticore.codeAdaption.utils.Adapt; + @Adapt(ref = "Entity", template = "Price$${}", genTemplate = "Generated$${}") + class LiteralDollar {} + """); - String fileName = baseDir + "invalid/" + filename; - ASTOrdinaryCompilationUnit ast = JavaLoader.loadJava(new File(fileName)); - validator.runCoCosPhase2(ast, cd); + validator.runAdapterCoCos(ast, cd); - Assertions.assertEquals(5, Log.getErrorCount()); - Log.getFindings().forEach(f -> Assertions.assertTrue(f.getMsg().startsWith(errorCode))); + Assertions.assertEquals(0, Log.getErrorCount()); } + + @Test + void generatedTemplateMustMatchReferenceArity() throws IOException { + ASTOrdinaryCompilationUnit ast = + javaSource( + "InvalidGeneratedTemplate.java", + """ + import de.monticore.codeAdaption.utils.Adapt; + @Adapt(ref = "Entity", template = "${}", genTemplate = "${}${}") + class InvalidGeneratedTemplate {} + """); + + validator.runAdapterCoCos(ast, cd); + + Assertions.assertEquals(1, Log.getErrorCount()); + Assertions.assertTrue(Log.getFindings().get(0).getMsg().startsWith("0xRC001")); + } + + @Test + void validationInitializesSourceTypesBeforeCheckingSupertypes() throws IOException { + Path sources = Files.createDirectory(tempDir.resolve("source-local-supertype")); + Files.writeString(sources.resolve("Base.java"), "class Base {}"); + Files.writeString(sources.resolve("Child.java"), "class Child extends Base {}"); + CodeValidator strictMembers = + new CodeValidator(cd, Set.of(IGNORE_NON_MATCHED_TYPE, IGNORE_NON_MATCHED_VAR)); + + Assertions.assertTrue(strictMembers.isValid(cd, sources)); + } + + @Test + void validationRejectsUnmatchedExternalSupertype() throws IOException { + Path sources = Files.createDirectory(tempDir.resolve("external-supertype")); + Files.writeString(sources.resolve("Child.java"), "class Child extends ExternalBase {}"); + CodeValidator strictMembers = + new CodeValidator(cd, Set.of(IGNORE_NON_MATCHED_TYPE, IGNORE_NON_MATCHED_VAR)); + + Assertions.assertFalse(strictMembers.isValid(cd, sources)); + } + + @Test + void validationCanIgnoreUnmatchedExternalSupertype() throws IOException { + Path sources = Files.createDirectory(tempDir.resolve("ignored-supertype")); + Files.writeString(sources.resolve("Child.java"), "class Child extends ExternalBase {}"); + CodeValidator ignoredMembers = + new CodeValidator( + cd, + Set.of( + IGNORE_NON_MATCHED_TYPE, + IGNORE_NON_MATCHED_TYPE_MEMBER, + IGNORE_NON_MATCHED_VAR)); + + Assertions.assertTrue(ignoredMembers.isValid(cd, sources)); + } + + private ASTOrdinaryCompilationUnit javaSource(String fileName, String source) throws IOException { + Path file = tempDir.resolve(fileName); + Files.writeString(file, source); + return JavaLoader.loadJava(file.toFile()); + } + } diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/App.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/App.cd index 8ed23820..f568ddfb 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/App.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/App.cd @@ -1,4 +1,4 @@ -import java.lang.String ; +import java.lang.String; classdiagram App { class Application; diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/UniApp.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/UniApp.cd index 85f72c87..d827c3b0 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/UniApp.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/UniApp.cd @@ -1,4 +1,4 @@ -import java.lang.String ; +import java.lang.String; classdiagram UniApp { diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/name/Entity.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/name/Entity.java index 4c712628..73ec020f 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/name/Entity.java +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/name/Entity.java @@ -1,7 +1,4 @@ - - - - -public class Entity { +public class Entity { String id; -} + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/EvaluationConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/EvaluationConc.cd new file mode 100644 index 00000000..34d3c1fc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/EvaluationConc.cd @@ -0,0 +1,19 @@ +classdiagram EvaluationConc { + class Project { + } + class Staff { + int staffID; + } + <> class Administration { + } + <> class Trainee { + int supervisorID; + } + class Employee { + <> int employeeID; + } + association staffEmployment Staff -- Employee; + association Staff -- Project; + <> association traineeProgram + Administration (hostAdm) <- (trainee) Trainee [0..*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/EvaluationOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/EvaluationOut.cd new file mode 100644 index 00000000..4b6f1501 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/EvaluationOut.cd @@ -0,0 +1,31 @@ +import java.lang.String; + +classdiagram EvaluationConc { + class Project; + + class Staff { + int staffID; + } + + <>class Administration { + String name; + } + + <>class Trainee extends Person { + int supervisorID; + } + + class Employee extends Person { + <>int employeeID; + } + + class Person { + String name; + int age; + } + + association staffEmployment Staff(partOf)<->(member)Employee [1..*]; + association Staff--Project; + <>association traineeProgram Administration(hostAdm)<-(trainee)Trainee[0..*]; + association administrationAssignment [1]Staff<->Administration [1]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/EvaluationRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/EvaluationRef.cd new file mode 100644 index 00000000..d560d8e4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/EvaluationRef.cd @@ -0,0 +1,22 @@ +import java.lang.String; + +classdiagram EvaluationRef { + class Person { + String name; + int age; + } + class Department { + String name; + } + class Employee extends Person { + int id; + } + class Intern extends Person { + int supervisorID; + } + class Staff { + } + association staffEmployment Staff (partOf) <-> (member) Employee [1..*]; + association departmentAssignment [1] Staff <-> Department [1]; + association internshipProgram Department -- (intern) Intern; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0001/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0001/Account.java new file mode 100644 index 00000000..3bd36114 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0001/Account.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationinsupertype; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Account"}, template = "${}") +public class Account { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0002/Person.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0002/Person.java new file mode 100644 index 00000000..d4a0b550 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0002/Person.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationinsupertype; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Person"}, template = "${}") +public class Person { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0003/A.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0003/A.java new file mode 100644 index 00000000..a97cd3a3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0003/A.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingcardinality; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"A"}, template = "${}") +public class A { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0004/B.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0004/B.java new file mode 100644 index 00000000..7ebe4e66 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0004/B.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingcardinality; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"B"}, template = "${}") +public class B { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0005/Department.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0005/Department.java new file mode 100644 index 00000000..bdd648ef --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0005/Department.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingcardinality; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Department"}, template = "${}") +public class Department { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0006/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0006/Employee.java new file mode 100644 index 00000000..c0aaaf78 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0006/Employee.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingcardinality; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Employee"}, template = "${}") +public class Employee { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0007/Project.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0007/Project.java new file mode 100644 index 00000000..667dcef8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0007/Project.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.assocnameimplicitnameadapt; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Project"}, template = "${}") +public class Project { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0008/Task.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0008/Task.java new file mode 100644 index 00000000..d2bbddbf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0008/Task.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.assocnameimplicitnameadapt; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Task"}, template = "${}") +public class Task { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0009/A.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0009/A.java new file mode 100644 index 00000000..8ea8119d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0009/A.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.associations; + +public class A { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0010/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0010/Builder.java new file mode 100644 index 00000000..b9931302 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0010/Builder.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattribute; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}") +public class Builder { + @Adapt(ref = {"Builder.attribute"}, template = "${}") + private Object attribute; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0011/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0011/DataClass.java new file mode 100644 index 00000000..3eb76ee1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0011/DataClass.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattribute; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { + @Adapt(ref = {"DataClass.attribute"}, template = "${}") + private Object attribute; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0012/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0012/Employee.java new file mode 100644 index 00000000..e4c1d7a2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0012/Employee.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.foreach; + +public class Employee { + private String firstName; + + private String lastName; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0013/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0013/Employee.java new file mode 100644 index 00000000..d7df51c5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0013/Employee.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.valid.adapter.attributeindeepsuperclass; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Employee"}, template = "${}") +public class Employee { + @Adapt(ref = {"Employee.firstName"}, template = "${}") + private String firstName; + + @Adapt(ref = {"Employee.lastName"}, template = "${}") + private String lastName; + + @Adapt(ref = {"Employee.number"}, template = "${}") + private int number; + + @Adapt(ref = {"Employee.salary"}, template = "${}") + private int salary; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0014/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0014/Employee.java new file mode 100644 index 00000000..457081cf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0014/Employee.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.valid.adapter.attributesmissing; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Employee"}, template = "${}") +public class Employee { + @Adapt(ref = {"Employee.number"}, template = "${}") + private int number; + + @Adapt(ref = {"Employee.salary"}, template = "${}") + private int salary; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0015/Bank.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0015/Bank.java new file mode 100644 index 00000000..fbfc5314 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0015/Bank.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Bank"}, template = "${}") +public class Bank { + @Adapt(ref = {"Bank.id"}, template = "${}") + private String id; + + @Adapt(ref = {"Bank.overallBalance"}, template = "${}") + private double overallBalance; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0016/BankAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0016/BankAccount.java new file mode 100644 index 00000000..b038d876 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0016/BankAccount.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking.singleinc.concrete.banking; + +public class BankAccount { + private String iban; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0017/SEPABank.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0017/SEPABank.java new file mode 100644 index 00000000..af1e9437 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0017/SEPABank.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking.singleinc.concrete.banking; + +public class SEPABank { + private String bic; + + private double totalMoney; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0018/Department.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0018/Department.java new file mode 100644 index 00000000..af99f822 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0018/Department.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.builder; + +public class Department { + private String managerName; + + private int depId; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0019/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0019/Employee.java new file mode 100644 index 00000000..c0d610ba --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0019/Employee.java @@ -0,0 +1,12 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.builder; + +public class Employee { + private String firstName; + + private String lastName; + + private int number; + + private int salary; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0020/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0020/DataClass.java new file mode 100644 index 00000000..87587bea --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0020/DataClass.java @@ -0,0 +1,15 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.getter_setter.adapter.datamodel; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { + @Adapt(ref = {"DataClass.attribute"}, template = "${}") + private Object attribute; + + @Adapt(ref = {"DataClass.getAttribute"}, template = "${}") + public Object getAttribute() { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0021/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0021/DataClass.java new file mode 100644 index 00000000..5a1be7f0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0021/DataClass.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.transitivedependencies.adapter.transitivedependencies; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0022/DataClassBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0022/DataClassBuilder.java new file mode 100644 index 00000000..0ba1da24 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0022/DataClassBuilder.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.transitivedependencies.adapter.transitivedependencies; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClassBuilder"}, template = "${}") +public class DataClassBuilder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0023/Person.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0023/Person.java new file mode 100644 index 00000000..20e3ec2d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0023/Person.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.inheritance.adapter.attributeinheritance; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Person"}, template = "${}") +public class Person { + @Adapt(ref = {"Person.number"}, template = "${}") + private int number; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0024/Teacher.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0024/Teacher.java new file mode 100644 index 00000000..2287be97 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0024/Teacher.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.inheritance.adapter.attributeinheritance; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Teacher"}, template = "${}") +public class Teacher extends Person { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0025/Placeholder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0025/Placeholder.java new file mode 100644 index 00000000..dc2605c6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0025/Placeholder.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.basic.valid.concrete.classmissing; + +public class Placeholder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0026/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0026/Builder.java new file mode 100644 index 00000000..0fea0315 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0026/Builder.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachtypesamereturntype; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}") +public class Builder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0027/BusinessAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0027/BusinessAccount.java new file mode 100644 index 00000000..5c725151 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0027/BusinessAccount.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parameterandreturntypemi; + +public class BusinessAccount { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0028/InstantTransaction.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0028/InstantTransaction.java new file mode 100644 index 00000000..709bb53b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0028/InstantTransaction.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parameterandreturntypemi; + +public class InstantTransaction { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0029/NormalTransaction.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0029/NormalTransaction.java new file mode 100644 index 00000000..9dcb7b5b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0029/NormalTransaction.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parameterandreturntypemi; + +public class NormalTransaction { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0030/PersonalAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0030/PersonalAccount.java new file mode 100644 index 00000000..5502c822 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/java/group-0030/PersonalAccount.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parameterandreturntypemi; + +public class PersonalAccount { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/shared-fixtures.tsv b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/shared-fixtures.tsv new file mode 100644 index 00000000..f8208c23 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/_shared/shared-fixtures.tsv @@ -0,0 +1,113 @@ +# case role shared output package +associations/AssociationInSuperTypeConc.cd adapter _shared/java/group-0001/Account.java Account.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationinsupertype; +methods/multiIncarnation/ParameterAndReturnTypeMIConc.cd adapter _shared/java/group-0001/Account.java Account.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; +methods/multiIncarnation/ParameterTypeMIConc.cd adapter _shared/java/group-0001/Account.java Account.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; +methods/multiIncarnation/ParameterTypeMIOneExistsConc.cd adapter _shared/java/group-0001/Account.java Account.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; +methods/multiIncarnation/ReturnTypeMIConc.cd adapter _shared/java/group-0001/Account.java Account.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; +methods/multiIncarnation/ReturnTypeMIOneExistsConc.cd adapter _shared/java/group-0001/Account.java Account.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; +associations/AssociationInSuperTypeConc.cd adapter _shared/java/group-0002/Person.java Person.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationinsupertype; +inheritance/MissingInheritanceConc.cd adapter _shared/java/group-0002/Person.java Person.java package de.monticore.codeAdaption.cdconcretization.inheritance.adapter.missinginheritance; +associations/AssociationMissingCardinalityConc.cd adapter _shared/java/group-0003/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingcardinality; +associations/AssociationMissingSimpleConc.cd adapter _shared/java/group-0003/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingsimple; +associations/AssociationReverseMatchConc.cd adapter _shared/java/group-0003/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationreversematch; +associations/AssociationSuperMatchingConc.cd adapter _shared/java/group-0003/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationsupermatching; +associations/TypeMIOneAssocExistsConc.cd adapter _shared/java/group-0003/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.typemioneassocexists; +helper/HelperConc.cd adapter _shared/java/group-0003/A.java A.java package de.monticore.codeAdaption.cdconcretization.helper.adapter.helper; +associations/AssociationMissingCardinalityConc.cd adapter _shared/java/group-0004/B.java B.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingcardinality; +associations/AssociationMissingSimpleConc.cd adapter _shared/java/group-0004/B.java B.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingsimple; +associations/AssociationReverseMatchConc.cd adapter _shared/java/group-0004/B.java B.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationreversematch; +associations/AssociationSuperMatchingConc.cd adapter _shared/java/group-0004/B.java B.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationsupermatching; +associations/TypeMIOneAssocExistsConc.cd adapter _shared/java/group-0004/B.java B.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.typemioneassocexists; +helper/HelperConc.cd adapter _shared/java/group-0004/B.java B.java package de.monticore.codeAdaption.cdconcretization.helper.adapter.helper; +associations/AssociationMissingCardinalityConc.cd adapter _shared/java/group-0005/Department.java Department.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingcardinality; +associations/AssociationMissingFinalConc.cd adapter _shared/java/group-0005/Department.java Department.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingfinal; +associations/AssociationMissingRolenameConc.cd adapter _shared/java/group-0005/Department.java Department.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingrolename; +associations/AssociationMissingSimpleConc.cd adapter _shared/java/group-0005/Department.java Department.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingsimple; +associations/AssociationMultipleTypeIncarnationConc.cd adapter _shared/java/group-0005/Department.java Department.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmultipletypeincarnation; +multipleIncarnation/BothAssocSidesMIConc.cd adapter _shared/java/group-0005/Department.java Department.java package de.monticore.codeAdaption.cdconcretization.multipleincarnation.adapter.bothassocsidesmi; +associations/AssociationMissingCardinalityConc.cd adapter _shared/java/group-0006/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingcardinality; +associations/AssociationMissingFinalConc.cd adapter _shared/java/group-0006/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingfinal; +associations/AssociationMissingRolenameConc.cd adapter _shared/java/group-0006/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingrolename; +associations/AssociationMissingSimpleConc.cd adapter _shared/java/group-0006/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmissingsimple; +associations/AssocNameImplicitNameAdaptConc.cd adapter _shared/java/group-0007/Project.java Project.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.assocnameimplicitnameadapt; +associations/AssocRoleImplicitNameAdaptConc.cd adapter _shared/java/group-0007/Project.java Project.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.assocroleimplicitnameadapt; +associations/AssocNameImplicitNameAdaptConc.cd adapter _shared/java/group-0008/Task.java Task.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.assocnameimplicitnameadapt; +associations/AssocRoleImplicitNameAdaptConc.cd adapter _shared/java/group-0008/Task.java Task.java package de.monticore.codeAdaption.cdconcretization.associations.adapter.assocroleimplicitnameadapt; +associations/AssociationInSuperTypeConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/AssociationMissingCardinalityConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/AssociationMissingFinalConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/AssociationMissingRolenameConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/AssociationMissingSimpleConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/AssociationMultipleTypeIncarnationConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/AssociationReverseMatchConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/AssociationSuperMatchingConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/AssocNameImplicitNameAdaptConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/AssocRoleImplicitNameAdaptConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +associations/TypeMIOneAssocExistsConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.associations; +helper/HelperConc.cd concrete _shared/java/group-0009/A.java A.java package de.monticore.codeAdaption.cdconcretization.helper; +attributes/forEach/ForEachAttributeConc.cd adapter _shared/java/group-0010/Builder.java Builder.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattribute; +attributes/forEach/ForEachAttributeNoTargetIncConc.cd adapter _shared/java/group-0010/Builder.java Builder.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattributenotargetinc; +types/forEach/ForEachTypeForEachAttributeConc.cd adapter _shared/java/group-0010/Builder.java Builder.java package de.monticore.codeAdaption.cdconcretization.types.foreach.adapter.foreachtypeforeachattribute; +attributes/forEach/ForEachAttributeConc.cd adapter _shared/java/group-0011/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattribute; +attributes/forEach/ForEachAttributeDifferentNameClassMIConc.cd adapter _shared/java/group-0011/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattributedifferentnameclassmi; +attributes/forEach/ForEachAttributeDifferentTypeConc.cd adapter _shared/java/group-0011/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattributedifferenttype; +attributes/forEach/ForEachAttributeNoTargetIncConc.cd adapter _shared/java/group-0011/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattributenotargetinc; +attributes/underspecified/AttributeTypeUnderspecifiedDifferentIncTypesConc.cd adapter _shared/java/group-0011/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.attributes.underspecified.adapter.attributetypeunderspecifieddifferentinctypes; +evaluation/builder/DataModelConc.cd adapter _shared/java/group-0011/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.evaluation.builder.adapter.datamodel; +methods/forEach/ForEachAttributeConc.cd adapter _shared/java/group-0011/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachattribute; +types/forEach/ForEachTypeForEachAttributeConc.cd adapter _shared/java/group-0011/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.types.foreach.adapter.foreachtypeforeachattribute; +attributes/forEach/ForEachAttributeConc.cd concrete _shared/java/group-0012/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach; +attributes/forEach/ForEachAttributeDifferentNameClassMIConc.cd concrete _shared/java/group-0012/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach; +attributes/forEach/ForEachAttributeDifferentNameConc.cd concrete _shared/java/group-0012/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach; +attributes/forEach/ForEachAttributeDifferentTypeConc.cd concrete _shared/java/group-0012/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach; +attributes/forEach/ForEachAttributeInheritanceConc.cd concrete _shared/java/group-0012/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach; +attributes/forEach/ForEachAttributeNoTargetIncConc.cd concrete _shared/java/group-0012/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.foreach; +attributes/underspecified/AttributeTypeUnderspecifiedDifferentIncTypesConc.cd concrete _shared/java/group-0012/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.underspecified; +attributes/underspecified/AttributeTypeUnderspecifiedNoIncConc.cd concrete _shared/java/group-0012/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.underspecified; +attributes/valid/AttributeInDeepSuperClassConc.cd adapter _shared/java/group-0013/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.valid.adapter.attributeindeepsuperclass; +attributes/valid/AttributeInSuperClassConc.cd adapter _shared/java/group-0013/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.valid.adapter.attributeinsuperclass; +attributes/valid/AttributesMissingConc.cd adapter _shared/java/group-0014/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.valid.adapter.attributesmissing; +attributes/valid/TwoAttributesMissingConc.cd adapter _shared/java/group-0014/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.attributes.valid.adapter.twoattributesmissing; +evaluation/banking/multiInc/BankingConc.cd adapter _shared/java/group-0015/Bank.java Bank.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking; +evaluation/banking/singleInc/BankingConc.cd adapter _shared/java/group-0015/Bank.java Bank.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking; +evaluation/banking/usageByExtension/BankingConc.cd adapter _shared/java/group-0015/Bank.java Bank.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking; +evaluation/banking2/BankingConc.cd adapter _shared/java/group-0015/Bank.java Bank.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking2.adapter.banking; +evaluation/banking/singleInc/BankingConc.cd concrete _shared/java/group-0016/BankAccount.java BankAccount.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking.singleinc.concrete.banking; +evaluation/banking/usageByExtension/BankingConc.cd concrete _shared/java/group-0016/BankAccount.java BankAccount.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking.usagebyextension.concrete.banking; +evaluation/banking2/BankingConc.cd concrete _shared/java/group-0016/BankAccount.java BankAccount.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking2; +evaluation/banking/singleInc/BankingConc.cd concrete _shared/java/group-0017/SEPABank.java SEPABank.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking.singleinc.concrete.banking; +evaluation/banking/usageByExtension/BankingConc.cd concrete _shared/java/group-0017/SEPABank.java SEPABank.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking.usagebyextension.concrete.banking; +evaluation/banking2/BankingConc.cd concrete _shared/java/group-0017/SEPABank.java SEPABank.java package de.monticore.codeAdaption.cdconcretization.evaluation.banking2; +evaluation/builder/DataModelConc.cd concrete _shared/java/group-0018/Department.java Department.java package de.monticore.codeAdaption.cdconcretization.evaluation.builder; +evaluation/getter-setter/DataModelConc.cd concrete _shared/java/group-0018/Department.java Department.java package de.monticore.codeAdaption.cdconcretization.evaluation.getter_setter; +evaluation/builder/DataModelConc.cd concrete _shared/java/group-0019/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.evaluation.builder; +evaluation/getter-setter/DataModelConc.cd concrete _shared/java/group-0019/Employee.java Employee.java package de.monticore.codeAdaption.cdconcretization.evaluation.getter_setter; +evaluation/getter-setter/DataModelConc.cd adapter _shared/java/group-0020/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.evaluation.getter_setter.adapter.datamodel; +methods/forEach/ForEachAttributeSameReturnTypeClassMIConc.cd adapter _shared/java/group-0020/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachattributesamereturntypeclassmi; +evaluation/transitiveDependencies/TransitiveDependenciesConc.cd adapter _shared/java/group-0021/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.evaluation.transitivedependencies.adapter.transitivedependencies; +types/forEach/ForEachTypeConc.cd adapter _shared/java/group-0021/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.types.foreach.adapter.foreachtype; +types/forEach/ForEachTypeInfixReplaceConc.cd adapter _shared/java/group-0021/DataClass.java DataClass.java package de.monticore.codeAdaption.cdconcretization.types.foreach.adapter.foreachtypeinfixreplace; +evaluation/transitiveDependencies/TransitiveDependenciesConc.cd adapter _shared/java/group-0022/DataClassBuilder.java DataClassBuilder.java package de.monticore.codeAdaption.cdconcretization.evaluation.transitivedependencies.adapter.transitivedependencies; +types/forEach/ForEachTypeInfixReplaceConc.cd adapter _shared/java/group-0022/DataClassBuilder.java DataClassBuilder.java package de.monticore.codeAdaption.cdconcretization.types.foreach.adapter.foreachtypeinfixreplace; +inheritance/AttributeInheritanceConc.cd adapter _shared/java/group-0023/Person.java Person.java package de.monticore.codeAdaption.cdconcretization.inheritance.adapter.attributeinheritance; +inheritance/AttributeTypeMismatchConc.cd adapter _shared/java/group-0023/Person.java Person.java package de.monticore.codeAdaption.cdconcretization.inheritance.adapter.attributetypemismatch; +inheritance/AttributeInheritanceConc.cd adapter _shared/java/group-0024/Teacher.java Teacher.java package de.monticore.codeAdaption.cdconcretization.inheritance.adapter.attributeinheritance; +inheritance/AttributeTypeMismatchConc.cd adapter _shared/java/group-0024/Teacher.java Teacher.java package de.monticore.codeAdaption.cdconcretization.inheritance.adapter.attributetypemismatch; +inheritance/MissingInheritanceConc.cd adapter _shared/java/group-0024/Teacher.java Teacher.java package de.monticore.codeAdaption.cdconcretization.inheritance.adapter.missinginheritance; +methods/basic/valid/ClassMissingConc.cd concrete _shared/java/group-0025/Placeholder.java Placeholder.java package de.monticore.codeAdaption.cdconcretization.methods.basic.valid.concrete.classmissing; +types/forEach/ForEachTypeConc.cd concrete _shared/java/group-0025/Placeholder.java Placeholder.java package de.monticore.codeAdaption.cdconcretization.types.foreach; +types/forEach/ForEachTypeForEachAttributeConc.cd concrete _shared/java/group-0025/Placeholder.java Placeholder.java package de.monticore.codeAdaption.cdconcretization.types.foreach; +types/forEach/ForEachTypeInfixReplaceConc.cd concrete _shared/java/group-0025/Placeholder.java Placeholder.java package de.monticore.codeAdaption.cdconcretization.types.foreach; +types/forEach/ForEachTypeNoTargetIncConc.cd concrete _shared/java/group-0025/Placeholder.java Placeholder.java package de.monticore.codeAdaption.cdconcretization.types.foreach; +methods/forEach/ForEachTypeSameReturnTypeConc.cd adapter _shared/java/group-0026/Builder.java Builder.java package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachtypesamereturntype; +types/forEach/ForEachTypeConc.cd adapter _shared/java/group-0026/Builder.java Builder.java package de.monticore.codeAdaption.cdconcretization.types.foreach.adapter.foreachtype; +methods/multiIncarnation/ParameterAndReturnTypeMIConc.cd concrete _shared/java/group-0027/BusinessAccount.java BusinessAccount.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parameterandreturntypemi; +methods/multiIncarnation/ParameterTypeMIConc.cd concrete _shared/java/group-0027/BusinessAccount.java BusinessAccount.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parametertypemi; +methods/multiIncarnation/ParameterTypeMIOneExistsConc.cd concrete _shared/java/group-0027/BusinessAccount.java BusinessAccount.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parametertypemioneexists; +methods/multiIncarnation/ParameterAndReturnTypeMIConc.cd concrete _shared/java/group-0028/InstantTransaction.java InstantTransaction.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parameterandreturntypemi; +methods/multiIncarnation/ReturnTypeMIConc.cd concrete _shared/java/group-0028/InstantTransaction.java InstantTransaction.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.returntypemi; +methods/multiIncarnation/ParameterAndReturnTypeMIConc.cd concrete _shared/java/group-0029/NormalTransaction.java NormalTransaction.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parameterandreturntypemi; +methods/multiIncarnation/ReturnTypeMIConc.cd concrete _shared/java/group-0029/NormalTransaction.java NormalTransaction.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.returntypemi; +methods/multiIncarnation/ParameterAndReturnTypeMIConc.cd concrete _shared/java/group-0030/PersonalAccount.java PersonalAccount.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parameterandreturntypemi; +methods/multiIncarnation/ParameterTypeMIConc.cd concrete _shared/java/group-0030/PersonalAccount.java PersonalAccount.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parametertypemi; +methods/multiIncarnation/ParameterTypeMIOneExistsConc.cd concrete _shared/java/group-0030/PersonalAccount.java PersonalAccount.java package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parametertypemioneexists; diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Department.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Department.java new file mode 100644 index 00000000..57757693 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Department.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.adapter.evaluation; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Department"}, template = "${}") +public class Department { + @Adapt(ref = {"Department.name"}, template = "${}") + private String name; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Employee.java new file mode 100644 index 00000000..2928b3c8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Employee.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.adapter.evaluation; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Employee"}, template = "${}") +public class Employee extends Person { + @Adapt(ref = {"Employee.id"}, template = "${}") + private int id; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Intern.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Intern.java new file mode 100644 index 00000000..31e28482 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Intern.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.adapter.evaluation; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Intern"}, template = "${}") +public class Intern extends Person { + @Adapt(ref = {"Intern.supervisorID"}, template = "${}") + private int supervisorID; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Person.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Person.java new file mode 100644 index 00000000..54e0a24c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Person.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.adapter.evaluation; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Person"}, template = "${}") +public class Person { + @Adapt(ref = {"Person.name"}, template = "${}") + private String name; + + @Adapt(ref = {"Person.age"}, template = "${}") + private int age; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Staff.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Staff.java new file mode 100644 index 00000000..453806d9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/adapter/Evaluation/Staff.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.adapter.evaluation; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Staff"}, template = "${}") +public class Staff { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocNameImplicitNameAdaptConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocNameImplicitNameAdaptConc.cd new file mode 100644 index 00000000..95622df1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocNameImplicitNameAdaptConc.cd @@ -0,0 +1,7 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram AssocNameImplicitNameAdaptConc { + <> class Ticket; + <> class Sprint; + // existing association without name — DefaultAssocCompleter copies and adapts it + association Sprint -> Ticket [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocNameImplicitNameAdaptOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocNameImplicitNameAdaptOut.cd new file mode 100644 index 00000000..9d0f4311 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocNameImplicitNameAdaptOut.cd @@ -0,0 +1,7 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram AssocNameImplicitNameAdaptConc { + <> class Ticket; + <> class Sprint; + // association name "taskAssignment" copied from reference and adapted: "task" -> "ticket" + association ticketAssignment Sprint -> Ticket [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocNameImplicitNameAdaptRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocNameImplicitNameAdaptRef.cd new file mode 100644 index 00000000..808123b4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocNameImplicitNameAdaptRef.cd @@ -0,0 +1,7 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram AssocNameImplicitNameAdaptRef { + class Task; + class Project; + // association name "taskAssignment" starts with uncapitalised "task" -> adapted to "ticketAssignment" + association taskAssignment Project -> Task [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocRoleImplicitNameAdaptConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocRoleImplicitNameAdaptConc.cd new file mode 100644 index 00000000..22239ab2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocRoleImplicitNameAdaptConc.cd @@ -0,0 +1,7 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram AssocRoleImplicitNameAdaptConc { + <> class Ticket; + <> class Sprint; + // existing association without role name — DefaultAssocCompleter adds and adapts it + association Sprint -> Ticket [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocRoleImplicitNameAdaptOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocRoleImplicitNameAdaptOut.cd new file mode 100644 index 00000000..e53a03b1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocRoleImplicitNameAdaptOut.cd @@ -0,0 +1,7 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram AssocRoleImplicitNameAdaptConc { + <> class Ticket; + <> class Sprint; + // role name "assignedTask" copied from reference and adapted: "Task" -> "Ticket" + association Sprint -> (assignedTicket) Ticket [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocRoleImplicitNameAdaptRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocRoleImplicitNameAdaptRef.cd new file mode 100644 index 00000000..e2ae2a7a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocRoleImplicitNameAdaptRef.cd @@ -0,0 +1,6 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram AssocRoleImplicitNameAdaptRef { + class Task; + class Project; + association Project -> (assignedTask) Task [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocSubtypeTargetConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocSubtypeTargetConc.cd new file mode 100644 index 00000000..f3d2dd2e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocSubtypeTargetConc.cd @@ -0,0 +1,7 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram AssocSubtypeTargetConc { + // concrete CD has the same types as the reference but no associations + class Container; + class Item; + class SpecialItem extends Item; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocSubtypeTargetOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocSubtypeTargetOut.cd new file mode 100644 index 00000000..c31a798b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocSubtypeTargetOut.cd @@ -0,0 +1,10 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram AssocSubtypeTargetConc { + class Container; + class Item; + class SpecialItem extends Item; + // both associations are added: SpecialItem extends Item, but Item [*] must not suppress + // adding a separate incarnation for the explicitly modelled SpecialItem association + association Container -> (items) Item [*]; + association Container -> (specialItems) SpecialItem [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocSubtypeTargetRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocSubtypeTargetRef.cd new file mode 100644 index 00000000..f761b4b6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssocSubtypeTargetRef.cd @@ -0,0 +1,8 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram AssocSubtypeTargetRef { + class Container; + class Item; + class SpecialItem extends Item; + association Container -> (items) Item [*]; + association Container -> (specialItems) SpecialItem [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationInSuperTypeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationInSuperTypeConc.cd new file mode 100644 index 00000000..c4d659c1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationInSuperTypeConc.cd @@ -0,0 +1,11 @@ +classdiagram AssociationInSuperTypeConc { + + abstract class AccountTop; + + class Account extends AccountTop; + + class Person ; + + association AccountTop -> Person[1]; + association Person -> Account[*]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationInSuperTypeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationInSuperTypeOut.cd new file mode 100644 index 00000000..b6365657 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationInSuperTypeOut.cd @@ -0,0 +1,12 @@ +classdiagram AssociationInSuperTypeConc { + + abstract class AccountTop; + + class Account extends AccountTop; + + class Person ; + + association AccountTop -> Person[1]; + association Person -> Account[*]; + // there is no association missing to be conform to reference CD. So the tool should not add any association +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationInSuperTypeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationInSuperTypeRef.cd new file mode 100644 index 00000000..e0098405 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationInSuperTypeRef.cd @@ -0,0 +1,8 @@ +classdiagram AssociationInSuperTypeRef { + class Account; + + class Person ; + + association Account -> Person[1]; + association Person -> Account[*] ; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingCardinalityConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingCardinalityConc.cd new file mode 100644 index 00000000..5ab2436b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingCardinalityConc.cd @@ -0,0 +1,12 @@ +classdiagram AssociationMissingCardinalityConc { + class Employee { + } + class Department { + } + class A { + } + class B { + } + association Employee <-> Department; + association A <-> B ; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingCardinalityOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingCardinalityOut.cd new file mode 100644 index 00000000..3615d936 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingCardinalityOut.cd @@ -0,0 +1,12 @@ +classdiagram AssociationMissingCardinalityConc { + class Employee { + } + class Department { + } + class A { + } + class B { + } + association [1..*] Employee <-> Department [1]; + association A <-> B [1]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingCardinalityRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingCardinalityRef.cd new file mode 100644 index 00000000..76a385d8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingCardinalityRef.cd @@ -0,0 +1,12 @@ +classdiagram AssociationMissingCardinalityRef { + class Employee { + } + class Department { + } + class A { + } + class B { + } + association A <-> B [1]; + association [1..*] Employee <-> Department [1]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingFinalConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingFinalConc.cd new file mode 100644 index 00000000..1d973cc0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingFinalConc.cd @@ -0,0 +1,7 @@ +classdiagram AssociationMissingFinalConc { + class Employee { + } + class Department { + } + association Employee (employed) -> Department [1]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingFinalOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingFinalOut.cd new file mode 100644 index 00000000..a433f8c3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingFinalOut.cd @@ -0,0 +1,6 @@ +classdiagram AssociationMissingFinalConc { + class Employee; + class Department; + + association [1..*] Employee (employed) <-> (workplace) Department [1]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingFinalRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingFinalRef.cd new file mode 100644 index 00000000..c2948e32 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingFinalRef.cd @@ -0,0 +1,7 @@ +classdiagram AssociationMissingFinalRef { + class Employee { + } + class Department { + } + association [1] Department (workplace) -> Employee [1..*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingRolenameConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingRolenameConc.cd new file mode 100644 index 00000000..30722477 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingRolenameConc.cd @@ -0,0 +1,7 @@ +classdiagram AssociationMissingRolenameConc { + class Employee { + } + class Department { + } + association Employee <-> Department; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingRolenameOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingRolenameOut.cd new file mode 100644 index 00000000..b712a5c7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingRolenameOut.cd @@ -0,0 +1,7 @@ +classdiagram AssociationMissingRolenameConc { + class Employee { + } + class Department { + } + association Employee (employed) <-> Department; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingRolenameRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingRolenameRef.cd new file mode 100644 index 00000000..6f9fb368 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingRolenameRef.cd @@ -0,0 +1,7 @@ +classdiagram AssociationMissingRolenameRef { + class Employee { + } + class Department { + } + association Employee (employed) <-> Department; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingSimpleConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingSimpleConc.cd new file mode 100644 index 00000000..6de9993d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingSimpleConc.cd @@ -0,0 +1,12 @@ +classdiagram AssociationMissingSimpleConc { + class Employee { + } + class Department { + } + class A { + + } + class B { + + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingSimpleOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingSimpleOut.cd new file mode 100644 index 00000000..d61307d4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingSimpleOut.cd @@ -0,0 +1,14 @@ +classdiagram AssociationMissingSimpleConc { + class Employee { + } + class Department { + } + class A { + + } + class B { + + } + association Employee -- Department; + association A (partOf) -- B; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingSimpleRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingSimpleRef.cd new file mode 100644 index 00000000..7dc266cc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMissingSimpleRef.cd @@ -0,0 +1,14 @@ +classdiagram AssociationMissingSimpleRef { + class Employee { + } + class Department { + } + class A { + + } + class B { + + } + association Employee -- Department; + association A (partOf) -- B; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMultipleTypeIncarnationConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMultipleTypeIncarnationConc.cd new file mode 100644 index 00000000..d9dfd665 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMultipleTypeIncarnationConc.cd @@ -0,0 +1,10 @@ +classdiagram AssocMultipleTypeIncarnationConc { + class Teacher { + } + <> class MathDept { + } + <> class ScienceDept { + } +} + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMultipleTypeIncarnationOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMultipleTypeIncarnationOut.cd new file mode 100644 index 00000000..0b70c335 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMultipleTypeIncarnationOut.cd @@ -0,0 +1,10 @@ +classdiagram AssocMultipleTypeIncarnationConc { + class Teacher; + + <>class MathDept; + <>class ScienceDept; + + association Teacher (hasTeacher) <-> (teachesIn_MathDept) MathDept; + association Teacher (hasTeacher) <-> (teachesIn_ScienceDept) ScienceDept; + +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMultipleTypeIncarnationRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMultipleTypeIncarnationRef.cd new file mode 100644 index 00000000..ec101a21 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationMultipleTypeIncarnationRef.cd @@ -0,0 +1,7 @@ +classdiagram AssocMultipleTypeIncarnationRef { + class Teacher { + } + class Department { + } + association Teacher (hasTeacher) <-> (teachesIn) Department; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationReverseMatchConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationReverseMatchConc.cd new file mode 100644 index 00000000..2f265d25 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationReverseMatchConc.cd @@ -0,0 +1,7 @@ +classdiagram AssociationReverseMatchConc { + class A { + } + class B { + } + association B <- A; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationReverseMatchOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationReverseMatchOut.cd new file mode 100644 index 00000000..db263d89 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationReverseMatchOut.cd @@ -0,0 +1,6 @@ +classdiagram AssociationReverseMatchConc { + class A; + class B; + + association [*] B <- (partOf) A; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationReverseMatchRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationReverseMatchRef.cd new file mode 100644 index 00000000..40b03ec4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationReverseMatchRef.cd @@ -0,0 +1,7 @@ +classdiagram AssociationReverseMatchRef { + class A { + } + class B { + } + association A (partOf) -> B [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationSuperMatchingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationSuperMatchingConc.cd new file mode 100644 index 00000000..bd61f4ea --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationSuperMatchingConc.cd @@ -0,0 +1,22 @@ +classdiagram AssociationSuperMatchingConc { + + class ASuperSuper1; + class ASuperSuper2; + class ASuper1 extends ASuperSuper1; + class ASuper2 extends ASuperSuper2; + class ASuper3; + + <> class A1 extends ASuper1; + <> class A2 extends ASuper2; + <> class A3 extends ASuper3; // this one is missing associations + + abstract class BSuperSuper1; + abstract class BSuperSuper2; + abstract class BSuper1 extends BSuperSuper1, BSuperSuper2; + + <> class B1 extends BSuper1; + <> class B2 extends BSuperSuper2; // this one is missing associations + + association ASuperSuper1 -> BSuperSuper1 [*]; + association ASuperSuper2 -> BSuperSuper1 [*]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationSuperMatchingOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationSuperMatchingOut.cd new file mode 100644 index 00000000..b3a27d92 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationSuperMatchingOut.cd @@ -0,0 +1,27 @@ +classdiagram AssociationSuperMatchingConc { + + class ASuperSuper1; + class ASuperSuper2; + class ASuper1 extends ASuperSuper1; + class ASuper2 extends ASuperSuper2; + class ASuper3; + + <> class A1 extends ASuper1; + <> class A2 extends ASuper2; + <> class A3 extends ASuper3; // this one is missing associations + + abstract class BSuperSuper1; + abstract class BSuperSuper2; + abstract class BSuper1 extends BSuperSuper1, BSuperSuper2; + + <> class B1 extends BSuper1; + <> class B2 extends BSuperSuper2; // this one is missing associations + + association ASuperSuper1 -> BSuperSuper1 [*]; + association ASuperSuper2 -> BSuperSuper1 [*]; + + association A3 -> B1 [*]; + association A3 -> B2 [*]; + association A1 -> B2 [*]; + association A2 -> B2 [*]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationSuperMatchingRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationSuperMatchingRef.cd new file mode 100644 index 00000000..dd183612 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/AssociationSuperMatchingRef.cd @@ -0,0 +1,6 @@ +classdiagram AssociationSuperMatchingRef { + class A; + class B; + + association A -> B [*]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/TypeMIOneAssocExistsConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/TypeMIOneAssocExistsConc.cd new file mode 100644 index 00000000..3a0cfcc4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/TypeMIOneAssocExistsConc.cd @@ -0,0 +1,8 @@ +classdiagram TypeMIOneAssocExistsConc { + + class A; + <> class B1; + <> class B2; + + association A -- (partOf) B1; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/TypeMIOneAssocExistsOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/TypeMIOneAssocExistsOut.cd new file mode 100644 index 00000000..b5c7faff --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/TypeMIOneAssocExistsOut.cd @@ -0,0 +1,9 @@ +classdiagram TypeMIOneAssocExistsConc { + + class A; + <> class B1; + <> class B2; + + association A -- (partOf) B1; + association A -- (partOf_B2) B2; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/TypeMIOneAssocExistsRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/TypeMIOneAssocExistsRef.cd new file mode 100644 index 00000000..8fbbe01c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/TypeMIOneAssocExistsRef.cd @@ -0,0 +1,7 @@ +classdiagram TypeMIOneAssocExistsRef { + + class A; + class B; + + association A -- (partOf) B; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssocSubtypeTarget/Container.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssocSubtypeTarget/Container.java new file mode 100644 index 00000000..cc744da1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssocSubtypeTarget/Container.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.assocsubtypetarget; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Container"}, template = "${}") +public class Container { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssocSubtypeTarget/Item.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssocSubtypeTarget/Item.java new file mode 100644 index 00000000..6161a4ec --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssocSubtypeTarget/Item.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.assocsubtypetarget; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Item"}, template = "${}") +public class Item { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssocSubtypeTarget/SpecialItem.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssocSubtypeTarget/SpecialItem.java new file mode 100644 index 00000000..c1ef6e27 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssocSubtypeTarget/SpecialItem.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.assocsubtypetarget; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"SpecialItem"}, template = "${}") +public class SpecialItem extends Item { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssociationMultipleTypeIncarnation/Teacher.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssociationMultipleTypeIncarnation/Teacher.java new file mode 100644 index 00000000..66554f71 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/adapter/AssociationMultipleTypeIncarnation/Teacher.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.associations.adapter.associationmultipletypeincarnation; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Teacher"}, template = "${}") +public class Teacher { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/concrete/B1.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/concrete/B1.java new file mode 100644 index 00000000..8ff56b05 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/concrete/B1.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.associations; + +public class B1 { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/concrete/B2.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/concrete/B2.java new file mode 100644 index 00000000..b29889fb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/associations/concrete/B2.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.associations; + +public class B2 { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeConc.cd new file mode 100644 index 00000000..75a16f5b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeConc.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram ForEachAttributeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameClassMIConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameClassMIConc.cd new file mode 100644 index 00000000..b668d5eb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameClassMIConc.cd @@ -0,0 +1,15 @@ +import java.lang.String; + +classdiagram ForEachAttributeDifferentNameClassMIConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + <> String managerName; + <> int depId; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameClassMIOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameClassMIOut.cd new file mode 100644 index 00000000..c20574f2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameClassMIOut.cd @@ -0,0 +1,24 @@ +import java.lang.String; + +classdiagram ForEachAttributeDifferentNameClassMIConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + <> String managerName; + <> int depId; + } + + class Builder { + <> String attrCopy_Employee_firstName; + <> String attrCopy_Employee_lastName; + <> int attrCopy_Employee_number; + <> int attrCopy_Employee_salary; + <> String attrCopy_Department_managerName; + <> int attrCopy_Department_depId; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameConc.cd new file mode 100644 index 00000000..92debce5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameConc.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram ForEachAttributeDifferentNameConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameOut.cd new file mode 100644 index 00000000..09eecf93 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameOut.cd @@ -0,0 +1,17 @@ +import java.lang.String; + +classdiagram ForEachAttributeDifferentNameConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + class Builder { + <> String attrCopy_firstName; + <> String attrCopy_lastName; + <> int attrCopy_number; + <> int attrCopy_salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameRef.cd new file mode 100644 index 00000000..db5ac590 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentNameRef.cd @@ -0,0 +1,12 @@ + +classdiagram ForEachAttributeDifferentNameRef { + class DataClass { + any attribute; + } + + class Builder { + // Incarnations will have the name "attrCopy_{DataClass.attribute incarnation}" because here + // target and source attribute have different names! + <> any attrCopy; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentTypeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentTypeConc.cd new file mode 100644 index 00000000..5b2c71e2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentTypeConc.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram ForEachAttributeDifferentTypeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentTypeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentTypeOut.cd new file mode 100644 index 00000000..c29d06ca --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentTypeOut.cd @@ -0,0 +1,17 @@ +import java.lang.String; + +classdiagram ForEachAttributeDifferentTypeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + class Builder { + <> boolean hasModifiedFirstName; + <> boolean hasModifiedLastName; + <> boolean hasModifiedNumber; + <> boolean hasModifiedSalary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentTypeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentTypeRef.cd new file mode 100644 index 00000000..725c5ddd --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeDifferentTypeRef.cd @@ -0,0 +1,12 @@ + +classdiagram ForEachAttributeDifferentTypeRef { + class DataClass { + any attribute; + } + + class Builder { + // Incarnations will all have the type 'boolean' as the referenced attribute does not have the + // same type as the annotated attribute! + <> boolean hasModifiedAttribute; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeInheritanceConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeInheritanceConc.cd new file mode 100644 index 00000000..f6c023f0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeInheritanceConc.cd @@ -0,0 +1,13 @@ +import java.lang.String; + +classdiagram ForEachAttributeInheritanceConc { + class Person { + <> String firstName; + <> String lastName; + } + + <> class Employee extends Person { + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeInheritanceOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeInheritanceOut.cd new file mode 100644 index 00000000..9546bcc6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeInheritanceOut.cd @@ -0,0 +1,20 @@ +import java.lang.String; + +classdiagram ForEachAttributeInheritanceConc { + class Person { + <> String firstName; + <> String lastName; + } + + <> class Employee extends Person { + <> int number; + <> int salary; + } + + class Builder { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeNoTargetIncConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeNoTargetIncConc.cd new file mode 100644 index 00000000..8477a472 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeNoTargetIncConc.cd @@ -0,0 +1,9 @@ +import java.lang.String; + +classdiagram ForEachAttributeNoTargetIncConc { + <> class Employee { + // NOTE: the attribute is not annotated with <>! + String firstName; + String lastName; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeNoTargetIncOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeNoTargetIncOut.cd new file mode 100644 index 00000000..d0b2fdad --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeNoTargetIncOut.cd @@ -0,0 +1,11 @@ +import java.lang.String; + +classdiagram ForEachAttributeNoTargetIncConc { + <> class Employee { + String firstName; + String lastName; + } + + class Builder { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeNoTargetIncRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeNoTargetIncRef.cd new file mode 100644 index 00000000..d75c46ab --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeNoTargetIncRef.cd @@ -0,0 +1,12 @@ + +classdiagram ForEachAttributeNoTargetIncRef { + class DataClass { + // TODO This example only works once we have the 'matchStructure' stereotype implemented + // TODO alternative: implement a stereotype 'optional' that cna be used to mark elements that must not be incarnated + <> any attribute; + } + + class Builder { + <> any attribute; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeOut.cd new file mode 100644 index 00000000..549f2a01 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeOut.cd @@ -0,0 +1,17 @@ +import java.lang.String; + +classdiagram ForEachAttributeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + class Builder { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeRef.cd new file mode 100644 index 00000000..e771c2e4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/ForEachAttributeRef.cd @@ -0,0 +1,12 @@ + +classdiagram ForEachAttributeRef { + class DataClass { + any attribute; + } + + class Builder { + // Incarnations will have the same name as the referenced attribute incarnations by convention + // because the referenced attribute has the same name as the annotated attribute! + <> any attribute; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/Builder.java new file mode 100644 index 00000000..d051cbdb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/Builder.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.foreach; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}") +public class Builder { + @Adapt(ref = {"Builder.attribute"}, template = "${}") + private Object attribute; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/DataClass.java new file mode 100644 index 00000000..e419a410 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/DataClass.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.foreach; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { + @Adapt(ref = {"DataClass.attribute"}, template = "${}") + private Object attribute; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/ForEachAttributeDifferentNameClassMI/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/ForEachAttributeDifferentNameClassMI/Builder.java new file mode 100644 index 00000000..738398f0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/ForEachAttributeDifferentNameClassMI/Builder.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattributedifferentnameclassmi; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}") +public class Builder { + @Adapt(ref = {"Builder.attrCopy"}, template = "${}") + private Object attrCopy; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/ForEachAttributeDifferentType/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/ForEachAttributeDifferentType/Builder.java new file mode 100644 index 00000000..05ce0e72 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/forEach/adapter/ForEachAttributeDifferentType/Builder.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.foreach.adapter.foreachattributedifferenttype; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}") +public class Builder { + @Adapt(ref = {"Builder.hasModifiedAttribute"}, template = "${}") + private boolean hasModifiedAttribute; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedDifferentIncTypesConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedDifferentIncTypesConc.cd new file mode 100644 index 00000000..ae30f34b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedDifferentIncTypesConc.cd @@ -0,0 +1,9 @@ +import java.lang.String; + +classdiagram AttributeTypeUnderspecifiedDifferentIncTypesConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int salery; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedDifferentIncTypesOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedDifferentIncTypesOut.cd new file mode 100644 index 00000000..bcbd85fe --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedDifferentIncTypesOut.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram AttributeTypeUnderspecifiedDifferentIncTypesConc { + // nothing changed. we just make sure the tool can process the input and does not add anything + <> class Employee { + <> String firstName; + <> String lastName; + <> int salery; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedNoIncConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedNoIncConc.cd new file mode 100644 index 00000000..467da550 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedNoIncConc.cd @@ -0,0 +1,9 @@ +import java.lang.String; + +classdiagram AttributeTypeUnderspecifiedNoIncConc { + <> class Employee { + // NOTE: the attribute is not annotated with <>! + String firstName; + String lastName; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedRef.cd new file mode 100644 index 00000000..d5b8a57c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/AttributeTypeUnderspecifiedRef.cd @@ -0,0 +1,6 @@ + +classdiagram AttributeTypeUnderspecifiedRef { + class DataClass { + any attribute; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/adapter/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/adapter/DataClass.java new file mode 100644 index 00000000..0980d1c5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/underspecified/adapter/DataClass.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.underspecified; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { + @Adapt(ref = {"DataClass.attribute"}, template = "${}") + private Object attribute; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInDeepSuperClassConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInDeepSuperClassConc.cd new file mode 100644 index 00000000..8503d2c1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInDeepSuperClassConc.cd @@ -0,0 +1,16 @@ +import java.lang.String; + +classdiagram AttributeInDeepSuperClassConc { + class Person { + String firstName; + String lastName; + } + + class AbstractEmployee extends Person { + String someOtherProperty; + } + + class Employee extends AbstractEmployee { + int number; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInDeepSuperClassOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInDeepSuperClassOut.cd new file mode 100644 index 00000000..7cb33549 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInDeepSuperClassOut.cd @@ -0,0 +1,17 @@ +import java.lang.String; + +classdiagram AttributeInDeepSuperClassConc { + class Person { + String firstName; + String lastName; + } + + class AbstractEmployee extends Person { + String someOtherProperty; + } + + class Employee extends AbstractEmployee { + int number; + int salary; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInDeepSuperClassRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInDeepSuperClassRef.cd new file mode 100644 index 00000000..e716e6ad --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInDeepSuperClassRef.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram AttributeInDeepSuperClassRef { + class Employee { + String firstName; + String lastName; + int number; + int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInSuperClassConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInSuperClassConc.cd new file mode 100644 index 00000000..ec00665a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInSuperClassConc.cd @@ -0,0 +1,12 @@ +import java.lang.String; + +classdiagram AttributeInSuperClassConc { + class Person { + String firstName; + String lastName; + } + + class Employee extends Person { + int number; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInSuperClassOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInSuperClassOut.cd new file mode 100644 index 00000000..bed54bad --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInSuperClassOut.cd @@ -0,0 +1,13 @@ +import java.lang.String; + +classdiagram AttributeInSuperClassConc { + class Person { + String firstName; + String lastName; + } + + class Employee extends Person { + int number; + int salary; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInSuperClassRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInSuperClassRef.cd new file mode 100644 index 00000000..bf3ea05a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributeInSuperClassRef.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram AttributeInSuperClassRef { + class Employee { + String firstName; + String lastName; + int number; + int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributesMissingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributesMissingConc.cd new file mode 100644 index 00000000..524b5160 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributesMissingConc.cd @@ -0,0 +1,5 @@ +classdiagram AttributesMissingConc { + class Employee { + int number; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributesMissingRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributesMissingRef.cd new file mode 100644 index 00000000..48c5d49b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/AttributesMissingRef.cd @@ -0,0 +1,6 @@ +classdiagram AttributesMissingRef { + class Employee { + int number; + int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingConc.cd new file mode 100644 index 00000000..5da89302 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingConc.cd @@ -0,0 +1,4 @@ +classdiagram TwoAttributesMissingConc { + class Employee { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingOneMatchConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingOneMatchConc.cd new file mode 100644 index 00000000..37605e83 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingOneMatchConc.cd @@ -0,0 +1,5 @@ +classdiagram TwoAttributesMissingOneMatchConc { + class Employee { + int number; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingOneMatchRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingOneMatchRef.cd new file mode 100644 index 00000000..72c4527b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingOneMatchRef.cd @@ -0,0 +1,7 @@ +classdiagram TwoAttributesMissingOneMatchRef { + class Employee { + int number; + int anotherNumber; + int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingRef.cd new file mode 100644 index 00000000..fc38d3da --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/TwoAttributesMissingRef.cd @@ -0,0 +1,6 @@ +classdiagram TwoAttributesMissingRef { + class Employee { + int number; + int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/adapter/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/adapter/Employee.java new file mode 100644 index 00000000..9b5513c3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/adapter/Employee.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.valid; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Employee"}, template = "${}") +public class Employee { + @Adapt(ref = {"Employee.firstName"}, template = "${}") + private String firstName; + + @Adapt(ref = {"Employee.lastName"}, template = "${}") + private String lastName; + + @Adapt(ref = {"Employee.number"}, template = "${}") + private int number; + + @Adapt(ref = {"Employee.salary"}, template = "${}") + private int salary; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/adapter/TwoAttributesMissingOneMatch/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/adapter/TwoAttributesMissingOneMatch/Employee.java new file mode 100644 index 00000000..bcf2d8dd --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/adapter/TwoAttributesMissingOneMatch/Employee.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.valid.adapter.twoattributesmissingonematch; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Employee"}, template = "${}") +public class Employee { + @Adapt(ref = {"Employee.number"}, template = "${}") + private int number; + + @Adapt(ref = {"Employee.anotherNumber"}, template = "${}") + private int anotherNumber; + + @Adapt(ref = {"Employee.salary"}, template = "${}") + private int salary; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/concrete/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/concrete/Employee.java new file mode 100644 index 00000000..8472bcf2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/attributes/valid/concrete/Employee.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.attributes.valid; + +public class Employee { + private int number; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Administration.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Administration.java new file mode 100644 index 00000000..cc3c5df0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Administration.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.concrete; + +public class Administration { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Employee.java new file mode 100644 index 00000000..bfaf32c2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Employee.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.concrete; + +public class Employee { + private int employeeID; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Project.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Project.java new file mode 100644 index 00000000..284f017c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Project.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.concrete; + +public class Project { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Staff.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Staff.java new file mode 100644 index 00000000..c3857556 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Staff.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.concrete; + +public class Staff { + private int staffID; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Trainee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Trainee.java new file mode 100644 index 00000000..411fbd50 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/concrete/Trainee.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.concrete; + +public class Trainee { + private int supervisorID; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/BankingRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/BankingRef.cd new file mode 100644 index 00000000..dbf0f299 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/BankingRef.cd @@ -0,0 +1,33 @@ +/* (c) https://github.com/MontiCore/monticore */ +import java.lang.String; + +classdiagram Banking { + + class Bank { + String id; + double overallBalance; // money of all accounts together + } + + class Account { + String id; + double balance; // money in the account + } + + class Customer { + String name; + String address; + String phoneNumber; + } + + // sends money from sourceAccount to targetAccount + class Transaction { + Account sourceAccount; + Account targetAccount; + double amount; + } + + association Bank -> Account [*]; + association Bank -> Customer [*]; + association [*] Account <-> Customer [*]; + association Account -> Transaction [*] <>; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/adapter/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/adapter/Account.java new file mode 100644 index 00000000..bf4cd2cf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/adapter/Account.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Account"}, template = "${}") +public class Account { + @Adapt(ref = {"Account.id"}, template = "${}") + private String id; + + @Adapt(ref = {"Account.balance"}, template = "${}") + private double balance; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/adapter/Customer.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/adapter/Customer.java new file mode 100644 index 00000000..f7060621 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/adapter/Customer.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Customer"}, template = "${}") +public class Customer { + @Adapt(ref = {"Customer.name"}, template = "${}") + private String name; + + @Adapt(ref = {"Customer.address"}, template = "${}") + private String address; + + @Adapt(ref = {"Customer.phoneNumber"}, template = "${}") + private String phoneNumber; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/adapter/Transaction.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/adapter/Transaction.java new file mode 100644 index 00000000..a78f2099 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/adapter/Transaction.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Transaction"}, template = "${}") +public class Transaction { + @Adapt(ref = {"Transaction.sourceAccount"}, template = "${}") + private Account sourceAccount; + + @Adapt(ref = {"Transaction.targetAccount"}, template = "${}") + private Account targetAccount; + + @Adapt(ref = {"Transaction.amount"}, template = "${}") + private double amount; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/BankingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/BankingConc.cd new file mode 100644 index 00000000..0a04a540 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/BankingConc.cd @@ -0,0 +1,22 @@ +/* (c) https://github.com/MontiCore/monticore */ +import java.lang.String; + +classdiagram Banking { + + <> class SEPABank { + <> String bic; + <> double privateAccountsOverallBalance; + <> double businessAccountsOverallBalance; + } + + <> class PrivateAccount { + <> String iban; + } + + <> class BusinessAccount { + <> String iban; + } + + <> class PrivateCustomer; + <> class BusinessCustomer; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/BankingOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/BankingOut.cd new file mode 100644 index 00000000..7745ea0a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/BankingOut.cd @@ -0,0 +1,49 @@ +/* (c) https://github.com/MontiCore/monticore */ +import java.lang.String; + +classdiagram Banking { + + <> class SEPABank { + <> String bic; + <> double privateAccountsOverallBalance; + <> double businessAccountsOverallBalance; + } + + <> class PrivateAccount { + <> String iban; + double balance; // money in the account + } + + <> class BusinessAccount { + <> String iban; + double balance; // money in the account + } + + <> class PrivateCustomer { + String name; + String address; + String phoneNumber; + } + + <> class BusinessCustomer { + String name; + String address; + String phoneNumber; + } + + // sends money from sourceAccount to targetAccount + class Transaction { + PrivateAccount sourceAccount; + PrivateAccount targetAccount; + double amount; + } + + association SEPABank -> PrivateAccount [*]; + association SEPABank -> BusinessAccount [*]; + association SEPABank -> PrivateCustomer [*]; + association SEPABank -> BusinessCustomer [*]; + association [*] PrivateAccount <-> PrivateCustomer [*]; + association [*] BusinessAccount <-> BusinessCustomer [*]; + association PrivateAccount -> Transaction [*] <>; + association BusinessAccount -> Transaction [*] <>; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/BusinessAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/BusinessAccount.java new file mode 100644 index 00000000..5be30eea --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/BusinessAccount.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking.multiinc.concrete.banking; + +public class BusinessAccount { + private String iban; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/BusinessCustomer.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/BusinessCustomer.java new file mode 100644 index 00000000..2cac03e8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/BusinessCustomer.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking.multiinc.concrete.banking; + +public class BusinessCustomer { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/PrivateAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/PrivateAccount.java new file mode 100644 index 00000000..9c7c1080 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/PrivateAccount.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking.multiinc.concrete.banking; + +public class PrivateAccount { + private String iban; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/PrivateCustomer.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/PrivateCustomer.java new file mode 100644 index 00000000..19e7cce4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/PrivateCustomer.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking.multiinc.concrete.banking; + +public class PrivateCustomer { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/SEPABank.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/SEPABank.java new file mode 100644 index 00000000..ec08a330 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/multiInc/concrete/Banking/SEPABank.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking.multiinc.concrete.banking; + +public class SEPABank { + private String bic; + + private double privateAccountsOverallBalance; + + private double businessAccountsOverallBalance; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/singleInc/BankingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/singleInc/BankingConc.cd new file mode 100644 index 00000000..e5d04992 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/singleInc/BankingConc.cd @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +import java.lang.String; + +classdiagram Banking { + + <> class SEPABank { + <> String bic; + <> double totalMoney; // money of all accounts together + } + + <> class BankAccount { + <> String iban; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/singleInc/BankingOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/singleInc/BankingOut.cd new file mode 100644 index 00000000..01b50e83 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/singleInc/BankingOut.cd @@ -0,0 +1,33 @@ +/* (c) https://github.com/MontiCore/monticore */ +import java.lang.String; + +classdiagram Banking { + + <> class SEPABank { + <> String bic; + <> double totalMoney; // money of all accounts together + } + + <> class BankAccount { + <> String iban; + double balance; // money in the account + } + + class Customer { + String name; + String address; + String phoneNumber; + } + + // sends money from sourceAccount to targetAccount + class Transaction { + BankAccount sourceBankAccount; + BankAccount targetBankAccount; + double amount; + } + + association SEPABank -> BankAccount [*]; + association SEPABank -> Customer [*]; + association [*] BankAccount <-> Customer [*]; + association BankAccount -> Transaction [*] <>; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/BankingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/BankingConc.cd new file mode 100644 index 00000000..5aabbc85 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/BankingConc.cd @@ -0,0 +1,17 @@ +/* (c) https://github.com/MontiCore/monticore */ +import java.lang.String; + +classdiagram Banking { + + <> class SEPABank { + <> String bic; + <> double totalMoney; // money of all accounts together + } + + <> class BankAccount { + <> String iban; + } + + class PrivateAccount extends BankAccount; + class BusinessAccount extends BankAccount; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/BankingOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/BankingOut.cd new file mode 100644 index 00000000..5da2d0fb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/BankingOut.cd @@ -0,0 +1,36 @@ +/* (c) https://github.com/MontiCore/monticore */ +import java.lang.String; + +classdiagram Banking { + + <> class SEPABank { + <> String bic; + <> double totalMoney; // money of all accounts together + } + + <> class BankAccount { + <> String iban; + double balance; // money in the account + } + + class PrivateAccount extends BankAccount; + class BusinessAccount extends BankAccount; + + class Customer { + String name; + String address; + String phoneNumber; + } + + // sends money from sourceAccount to targetAccount + class Transaction { + BankAccount sourceBankAccount; + BankAccount targetBankAccount; + double amount; + } + + association SEPABank -> BankAccount [*]; + association SEPABank -> Customer [*]; + association [*] BankAccount <-> Customer [*]; + association BankAccount -> Transaction [*] <>; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/concrete/Banking/BusinessAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/concrete/Banking/BusinessAccount.java new file mode 100644 index 00000000..0b35c4d8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/concrete/Banking/BusinessAccount.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking.usagebyextension.concrete.banking; + +public class BusinessAccount extends BankAccount { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/concrete/Banking/PrivateAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/concrete/Banking/PrivateAccount.java new file mode 100644 index 00000000..609ff3be --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking/usageByExtension/concrete/Banking/PrivateAccount.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking.usagebyextension.concrete.banking; + +public class PrivateAccount extends BankAccount { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/BankingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/BankingConc.cd new file mode 100644 index 00000000..946f8399 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/BankingConc.cd @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +import java.lang.String; + +classdiagram BankingConc { + + <> class SEPABank { + <> String bic; + <> double totalMoney; // money of all accounts together + } + + <> class BankAccount { + <> String iban; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/BankingOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/BankingOut.cd new file mode 100644 index 00000000..e8657333 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/BankingOut.cd @@ -0,0 +1,43 @@ +/* (c) https://github.com/MontiCore/monticore */ +import java.lang.String; + +classdiagram BankingConc { + + <> class SEPABank implements Auditable { + <> String bic; + <> double totalMoney; // money of all accounts together + } + + <> abstract class BankAccount implements Auditable { + <> String iban; + double balance; + AccountStatus status; + void withdraw(double amount); + void deposit(double amount); + void transfer(BankAccount targetBankAccount, double amount); + } + + interface Auditable { + String generateReport(); + } + + class SavingsAccount extends BankAccount; + class CheckingAccount extends BankAccount; + + enum AccountStatus { + PENDING, ACTIVE, CLOSED; + } + + class Customer; + + class Transaction { + double amount; + } + + association SEPABank -> BankAccount [*]; + association allCustomers SEPABank -> Customer [*]; + association [*] BankAccount <-> Customer [*]; + association BankAccount -> Transaction [*] {ordered}; + association Transaction -> (source) BankAccount [1]; + association Transaction -> (target) BankAccount [1]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/BankingRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/BankingRef.cd new file mode 100644 index 00000000..0008ca32 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/BankingRef.cd @@ -0,0 +1,42 @@ +import java.lang.String; + +classdiagram BankingRef { + + interface Auditable { + String generateReport(); + } + + class Bank implements Auditable { + String id; + double overallBalance; + } + + abstract class Account implements Auditable { + String id; + double balance; + AccountStatus status; + void withdraw(double amount); + void deposit(double amount); + void transfer(Account targetAccount, double amount); + } + + class SavingsAccount extends Account; + class CheckingAccount extends Account; + + enum AccountStatus { + PENDING, ACTIVE, CLOSED; + } + + class Customer; + + class Transaction { + double amount; + } + + association Bank -> Account [*]; + association allCustomers Bank -> Customer [*]; + association [*] Account <-> Customer [*]; + association Account -> Transaction [*] {ordered}; + association Transaction -> (source) Account [1]; + association Transaction -> (target) Account [1]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Bank.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Bank.java new file mode 100644 index 00000000..a5869fc0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Bank.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking2; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Bank"}, template = "${}") +public class Bank { + @Adapt(ref = {"Bank.id"}, template = "${}") + private String id; + + @Adapt(ref = {"Bank.overallBalance"}, template = "${}") + private double overallBalance; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Account.java new file mode 100644 index 00000000..cd528bc3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Account.java @@ -0,0 +1,28 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking2.adapter.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Account"}, template = "${}") +public class Account { + @Adapt(ref = {"Account.id"}, template = "${}") + private String id; + + @Adapt(ref = {"Account.balance"}, template = "${}") + private double balance; + + @Adapt(ref = {"Account.status"}, template = "${}") + private AccountStatus status; + + @Adapt(ref = {"Account.withdraw"}, template = "${}") + public void withdraw(double amount) { + } + + @Adapt(ref = {"Account.deposit"}, template = "${}") + public void deposit(double amount) { + } + + @Adapt(ref = {"Account.transfer"}, template = "${}") + public void transfer(Account targetAccount, double amount) { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/AccountStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/AccountStatus.java new file mode 100644 index 00000000..42455197 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/AccountStatus.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking2.adapter.banking; + +public enum AccountStatus { + PENDING, + ACTIVE, + CLOSED; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Auditable.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Auditable.java new file mode 100644 index 00000000..58a536c0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Auditable.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking2.adapter.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Auditable"}, template = "${}") +public interface Auditable { + @Adapt(ref = {"Auditable.generateReport"}, template = "${}") + String generateReport(); + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/CheckingAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/CheckingAccount.java new file mode 100644 index 00000000..9472122d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/CheckingAccount.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking2.adapter.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"CheckingAccount"}, template = "${}") +public class CheckingAccount extends Account { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Customer.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Customer.java new file mode 100644 index 00000000..9728d941 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Customer.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking2.adapter.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Customer"}, template = "${}") +public class Customer { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/SavingsAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/SavingsAccount.java new file mode 100644 index 00000000..002f415e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/SavingsAccount.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking2.adapter.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"SavingsAccount"}, template = "${}") +public class SavingsAccount extends Account { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Transaction.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Transaction.java new file mode 100644 index 00000000..c713e110 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/banking2/adapter/Banking/Transaction.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.banking2.adapter.banking; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Transaction"}, template = "${}") +public class Transaction { + @Adapt(ref = {"Transaction.amount"}, template = "${}") + private double amount; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/BuilderAndMillOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/BuilderAndMillOut.cd new file mode 100644 index 00000000..2dfeeed3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/BuilderAndMillOut.cd @@ -0,0 +1,42 @@ +import java.lang.String; + +classdiagram DataModelConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + <> String managerName; + <> int depId; + } + + <> + class EmployeeBuilder { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + <> EmployeeBuilder firstName(String firstName); + <> EmployeeBuilder lastName(String lastName); + <> EmployeeBuilder number(int number); + <> EmployeeBuilder salary(int salary); + Employee build(); + } + + <> + class DepartmentBuilder { + <> String managerName; + <> int depId; + <> DepartmentBuilder managerName(String managerName); + <> DepartmentBuilder depId(int depId); + Department build(); + } + + class Mill { + <> DepartmentBuilder departmentBuilder(); + <> EmployeeBuilder employeeBuilder(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/BuilderAndMillRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/BuilderAndMillRef.cd new file mode 100644 index 00000000..016e3d5e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/BuilderAndMillRef.cd @@ -0,0 +1,20 @@ +import java.lang.String; + +classdiagram BuilderAndMillRef { + class DataClass { + // TODO use <> here once it is implemented + any attribute; + } + + <> class DataClassBuilder { + // Incarnations will have the same name as the referenced attribute incarnations by convention + // because the referenced attribute has the same name as the annotated attribute! + <> any attribute; + <> DataClassBuilder attribute(any attribute); + DataClass build(); + } + + class Mill { + <> DataClassBuilder dataClassBuilder(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/DataModelConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/DataModelConc.cd new file mode 100644 index 00000000..6b9f3357 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/DataModelConc.cd @@ -0,0 +1,17 @@ +import java.lang.String; + +classdiagram DataModelConc { + <> class Employee { + // TODO remove attribute mappings once <> is implemented + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + // TODO remove attribute mappings once <> is implemented + <> String managerName; + <> int depId; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/adapter/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/adapter/DataClass.java new file mode 100644 index 00000000..2dfd0aa9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/adapter/DataClass.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.builder; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { + @Adapt(ref = {"DataClass.attribute"}, template = "${}") + private Object attribute; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/adapter/DataModel/DataClassBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/adapter/DataModel/DataClassBuilder.java new file mode 100644 index 00000000..f9db617f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/adapter/DataModel/DataClassBuilder.java @@ -0,0 +1,20 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.builder.adapter.datamodel; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClassBuilder"}, template = "${}") +public class DataClassBuilder { + @Adapt(ref = {"DataClassBuilder.attribute"}, template = "${}") + private Object attribute; + + @Adapt(ref = {"DataClassBuilder.attribute"}, template = "${}") + public DataClassBuilder attribute(Object attribute) { + return null; + } + + @Adapt(ref = {"DataClassBuilder.build"}, template = "${}") + public DataClass build() { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/adapter/DataModel/Mill.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/adapter/DataModel/Mill.java new file mode 100644 index 00000000..4c19fa67 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/builder/adapter/DataModel/Mill.java @@ -0,0 +1,12 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.builder.adapter.datamodel; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Mill"}, template = "${}") +public class Mill { + @Adapt(ref = {"Mill.dataClassBuilder"}, template = "${}") + public DataClassBuilder dataClassBuilder() { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/MicroserviceConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/MicroserviceConc.cd new file mode 100644 index 00000000..aeb2eee3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/MicroserviceConc.cd @@ -0,0 +1,6 @@ +classdiagram MicroserviceConc { + <> class UserService; + <> class OrderService; + <> class ProductService; + <> class InvoiceService; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/MicroserviceOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/MicroserviceOut.cd new file mode 100644 index 00000000..a6f1b4b6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/MicroserviceOut.cd @@ -0,0 +1,31 @@ +import java.lang.String; + +classdiagram MicroserviceConc { + <> class UserService { + <> void sendToUserService(String message); + <> void sendToOrderService(String message); + <> void sendToProductService(String message); + <> void sendToInvoiceService(String message); + } + + <> class OrderService { + <> void sendToUserService(String message); + <> void sendToOrderService(String message); + <> void sendToProductService(String message); + <> void sendToInvoiceService(String message); + } + + <> class ProductService { + <> void sendToUserService(String message); + <> void sendToOrderService(String message); + <> void sendToProductService(String message); + <> void sendToInvoiceService(String message); + } + + <> class InvoiceService { + <> void sendToUserService(String message); + <> void sendToOrderService(String message); + <> void sendToProductService(String message); + <> void sendToInvoiceService(String message); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/MicroserviceRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/MicroserviceRef.cd new file mode 100644 index 00000000..b8f04acb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/MicroserviceRef.cd @@ -0,0 +1,7 @@ +import java.lang.String; + +classdiagram MicroserviceRef { + class Microservice { + <> void sendToMicroservice(String message); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/adapter/Microservice/Microservice.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/adapter/Microservice/Microservice.java new file mode 100644 index 00000000..dcf36796 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/adapter/Microservice/Microservice.java @@ -0,0 +1,11 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.cross_references.adapter.microservice; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Microservice"}, template = "${}") +public class Microservice { + @Adapt(ref = {"Microservice.sendToMicroservice"}, template = "${}") + public void sendToMicroservice(String message) { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/InvoiceService.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/InvoiceService.java new file mode 100644 index 00000000..2aefa7c8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/InvoiceService.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.cross_references; + +public class InvoiceService { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/OrderService.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/OrderService.java new file mode 100644 index 00000000..51a1017b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/OrderService.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.cross_references; + +public class OrderService { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/ProductService.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/ProductService.java new file mode 100644 index 00000000..0e43103b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/ProductService.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.cross_references; + +public class ProductService { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/UserService.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/UserService.java new file mode 100644 index 00000000..2ccb999d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/cross-references/concrete/UserService.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.cross_references; + +public class UserService { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/crud-backend/CRUDBackendOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/crud-backend/CRUDBackendOut.cd new file mode 100644 index 00000000..f436916f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/crud-backend/CRUDBackendOut.cd @@ -0,0 +1,80 @@ +import java.lang.String; +import java.util.List; +import java.util.Optional; + +classdiagram DomainModel { + + <> class Employee { + <> String id; + <> String taxId; + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + <> String managerName; + <> int depId; + } + + class HttpResponse; + + <> class DepartmentRepository { + <> Optional findByDepId(int depId); + List findAll(); + Department save(Department department); + <> void removeByDepId(int depId); + + } + + <> class EmployeeRepository { + <> Optional findById(String id); + <> Optional findByTaxId(String taxId); + List findAll(); + Employee save(Employee employee); + <> void removeById(String id); + <> void removeByTaxId(String taxId); + } + + <> class EmployeeController { + <> HttpResponse getById(String id); + <> HttpResponse getByTaxId(String taxId); + HttpResponse getAll(); + HttpResponse create(CreateEmployeeData data); + <> HttpResponse updateById(String id, UpdateEmployeeData data); + <> HttpResponse updateByTaxId(String taxId, UpdateEmployeeData data); + <> HttpResponse removeById(String id); + <> HttpResponse removeByTaxId(String taxId); + } + + <> class DepartmentController { + <> HttpResponse getByDepId(int depId); + HttpResponse getAll(); + HttpResponse create(CreateDepartmentData data); + <> HttpResponse updateByDepId(int depId, UpdateDepartmentData data); + <> HttpResponse removeByDepId(int depId); + } + + <> class CreateEmployeeData { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class UpdateEmployeeData { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class CreateDepartmentData { + <> String managerName; + } + + <> class UpdateDepartmentData { + <> String managerName; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/crud-backend/CRUDBackendRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/crud-backend/CRUDBackendRef.cd new file mode 100644 index 00000000..c31aa29a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/crud-backend/CRUDBackendRef.cd @@ -0,0 +1,35 @@ +import java.util.List; +import java.util.Optional; + +classdiagram CRUDBackendRef { + + class Entity { + any id; + any attribute; + } + + <> class EntityRepository { + <> Optional findById(any id); + List findAll(); + Entity save(Entity entity); + <> void removeById(any id); + } + + <> class EntityController { + <> HttpResponse getById(any id); + HttpResponse getAll(); + HttpResponse create(CreateEntityData data); + <> HttpResponse updateById(any id, UpdateEntityData data); + <> HttpResponse removeById(any id); + } + + <> class CreateEntityData { + <> any attribute; + } + + <> class UpdateEntityData { + <> any attribute; + } + + class HttpResponse; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/crud-backend/DomainModel.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/crud-backend/DomainModel.cd new file mode 100644 index 00000000..d6006970 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/crud-backend/DomainModel.cd @@ -0,0 +1,17 @@ +import java.lang.String; + + classdiagram DomainModel { + <> class Employee { + <> String id; + <> String taxId; + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + <> String managerName; + <> int depId; + } + } diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/DataModelConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/DataModelConc.cd new file mode 100644 index 00000000..6b9f3357 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/DataModelConc.cd @@ -0,0 +1,17 @@ +import java.lang.String; + +classdiagram DataModelConc { + <> class Employee { + // TODO remove attribute mappings once <> is implemented + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + // TODO remove attribute mappings once <> is implemented + <> String managerName; + <> int depId; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/GetterOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/GetterOut.cd new file mode 100644 index 00000000..cc000b80 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/GetterOut.cd @@ -0,0 +1,23 @@ +import java.lang.String; + +classdiagram DataModelConc { + <> class Employee { + // TODO remove attribute mappings once <> is implemented + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + <> String getFirstName(); + <> String getLastName(); + <> int getNumber(); + <> int getSalary(); + } + + <> class Department { + // TODO remove attribute mappings once <> is implemented + <> String managerName; + <> int depId; + <> String getManagerName(); + <> int getDepId(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/GetterRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/GetterRef.cd new file mode 100644 index 00000000..0ef9d9b5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/GetterRef.cd @@ -0,0 +1,8 @@ + +classdiagram GetterRef { + class DataClass { + // TODO use <> here once it is implemented + any attribute; + <> any getAttribute(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/SetterOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/SetterOut.cd new file mode 100644 index 00000000..2fd430e7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/SetterOut.cd @@ -0,0 +1,23 @@ +import java.lang.String; + +classdiagram DataModelConc { + <> class Employee { + // TODO remove attribute mappings once <> is implemented + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + <> void setFirstName(String firstName); + <> void setLastName(String lastName); + <> void setNumber(int number); + <> void setSalary(int salary); + } + + <> class Department { + // TODO remove attribute mappings once <> is implemented + <> String managerName; + <> int depId; + <> void setManagerName(String managerName); + <> void setDepId(int depId); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/SetterRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/SetterRef.cd new file mode 100644 index 00000000..2848a165 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/SetterRef.cd @@ -0,0 +1,8 @@ + +classdiagram SetterRef { + class DataClass { + // TODO use <> here once it is implemented + any attribute; + <> void setAttribute(any attribute); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/adapter/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/adapter/DataClass.java new file mode 100644 index 00000000..c4fdf660 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/getter-setter/adapter/DataClass.java @@ -0,0 +1,15 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.getter-setter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { + @Adapt(ref = {"DataClass.attribute"}, template = "${}") + private Object attribute; + + @Adapt(ref = {"DataClass.getAttribute"}, template = "${}") + public Object getAttribute() { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/EmptyConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/EmptyConc.cd new file mode 100644 index 00000000..0b713592 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/EmptyConc.cd @@ -0,0 +1,3 @@ +classdiagram EmptyConc { + +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/EmptyConcOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/EmptyConcOut.cd new file mode 100644 index 00000000..947d2def --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/EmptyConcOut.cd @@ -0,0 +1,1455 @@ +import java.lang.String; +import java.lang.Long; +import java.lang.Integer; +import java.lang.Boolean; +import java.util.List; +import java.util.Optional; +import java.time.ZonedDateTime; +/* (c) https://github.com/MontiCore/monticore */ +/* adapted and customized by (c) MaCoCo, ein RWTH Aachen projekt */ + +// No packages supported yet in CD completion! +//package de.macoco.be.domain; + + + +classdiagram EmptyConc { + + //---------------------------------------------- + //--------------- PERSONAL --------------------- + //---------------------------------------------- + + /** + * Person ist die Zentrale Klasse des Personal-Komplexes. + **/ + class Person { + String vorname; + Optional vorsatzwort; + String nachname; + String kuerzel; // Abgeleitet analog wie bei SAP: 3 Vor- 3 Nachnamenbuchstaben + Optional personalnummer; + Optional gebDatum; + Optional beschBeginn; + Optional beschEnde; + List kommentar; + boolean istAktiv; + boolean istStundenzettelpflichtig = false; + Optional stundenzettelpflichtigVon; + Optional stundenzettelpflichtigBis; // TODO: brauchen wir nicht mehr + Optional ueberStundenUebertrag; + boolean darfWochenendarbeiten; + // Start WZL: + Optional hoechstbeschaeftigungBis; + List staatsangehoerigkeiten; + Optional telefonnummer; + Optional arbeitserlaubnisBis; + boolean extern; + Optional titel; + Optional rufname; + Optional adresse; + Optional email; + Optional geburtsname; + Optional geschlecht; + Optional lBVNummer; + Optional entfristung; + <> + Optional qualifikationstitel; + boolean speicherungGewuenscht = false; + <> + Optional urlaubskommentar; + Optional aenderungsdatum; + } + + association [1] Person -> (anstellungsarten) Anstellungsart [*]; + association [*] Person -> (vorgesetzte) Person [*]; + association [1] Person -> (notiz) Freitext [0..1]; + + //Für Studentenzettel: + association [1] Person -> (jahresurlaubstage) Jahresurlaub [*]; + association [1] Person -> (zusatzurlaubstage) Sonderurlaub [*]; + association [1] Person -> (stundenzettel) Stundenzettel [*]; + association [1] Person -> (abwesenheiten) Abwesenheit [*]; + + <> + association [1] Person -> (user) MacocoUser [0..1]; + + + //---------------------------------------------- + // Person -> *Anstellungsart + + class Anstellungsart { + BeschaeftigungsArt beschArt; + } + + association [1] Anstellungsart -> (vertraege) Vertrag [*]; + association [1] Anstellungsart -> (anstellungsformen) Anstellungsform [*]; + + enum BeschaeftigungsArt { + WiMi("Wissenschaftliche/r Mitarbeiter/in (WiMi)"), + HiWi("Hilfskraft (HiWi)"), + BTV("Beschäftigte/r in Technik und Verwaltung (BTV)"), + BEAMTE("Beamte/r"), + AZUBI("Azubi/ne"), + PLAN; + } + + //---------------------------------------------- + // Person -> *Anstellungsart -> *Vertrag + // eine direkte Verbindung zwischen Person und Vertrag existiert nicht. + + class Vertrag { // spiegelt den Vertrag der Hochschule wieder + ZonedDateTime vertragsBeginn; + ZonedDateTime vertragsEnde; + boolean aenderungsvertrag; + /String vertragsStatus; // Aktiv, Planung, Abgelaufen // TODO: change String to enum + List kommentar; + ZahlenWert planUmfang; + Optional arbeitsstundenProWoche; //Stundenzettel + boolean kuendigungsschutz; // WZL + Optional vertragsgrundlage; // WZL / TODO: change to enum + Optional aktion; // WZL / TODO: change to enum + Optional aktionsDatum; // WZL / TODO: change to enum + } + + association [1] Vertrag -> (kostenstellen) Kostenstelle [*]; + + //---------------------------------------------- + // Person -> *Anstellungsart -> Anstellungsform + + /** + * Beschreibt alle wesentlichen Merkmale einer Anstellung. + * Entgeltgruppe, Stufe, etc. + **/ + class Anstellungsform { + boolean erstanstellung; + Optional entgeltGruppe; // { TVL-13} Für Hiwis: {SHK (default), WHB, WHK} + Optional erfahrungsStufe; // 1- 6 ; sowie Spezialfälle (TVL Ü+); + boolean unbefristet; + ZonedDateTime anstellungVon; + Optional anstellungBis; + long gehaltCent; // evtl. Schätzgehalt in Zukunft + boolean istEigenerReferenzwert; + List kommentar; + Optional berufsgruppe; // WZL / TODO: change to enum + Optional aktion; // WZL / TODO: change to enum + Optional aktionsDatum; // WZL / TODO: change to enum + } + + //---------------------------------------------- + // Person -> *Anstellungsart -> *Vertrag -> *Kostenstelle + + class Kostenstelle { + ZonedDateTime verbuchungsBeginn; + ZonedDateTime verbuchungsEnde; + KostenstelleBezeichnung bezeichnung; + List kommentar; + ZahlenWert beschaeftigungsUmfang; + boolean buchungenNeuErzeugen; + boolean buchungenLoeschen; + boolean gesperrt; + } + + enum KostenstelleBezeichnung { + NONE(""), + AN_INSTITUT("An-Institut"), + GMBH("GmbH"), + ANDERER_LEHRSTUHL, + ANDERES_INSTITUT, + VORUEBERGEHEND_ABWESEND("Vorübergehend Abwesend"), + ANDERE_FINANZIERUNG; + } + + enum Zuweisungsart { + KONTO("Kontenzuweisung"), + STELLENZUWEISUNG, + PLANSTELLE, + SONSTIGES; + } + + association [*] Kostenstelle -> (personalBudget) Budget [0..1]; + association Kostenstelle -> (stellenzuweisung) Stellenzuweisung [0..1]; + association Kostenstelle -> (planstelle) Planstelle [0..1]; + <> + association [0..1] Kostenstelle -> (personalBuchungen) Buchung [*]; + + // Person -> *Anstellungsart -> *Vertrag -> *Kostenstelle -> ?Planstelle + + class Planstelle { + String bezeichnung; + Optional minEntgeltgruppe; + Optional minEntgeltstufe; + Optional maxEntgeltgruppe; + Optional maxEntgeltstufe; + Optional verfuegbarVon; + Optional verfuegbarBis; + Optional kommentar; + ZahlenWert planUmfang; + boolean aktiv; + } + + association Planstelle -> (konto) Konto [0..1]; + + //---------------------------------------------- + + /** + * Repräsentiert verschiedene Arten von monetären Haben + * @attribute wert ist jeweils unterschiedlich zu interpretieren: + * EURO heisst, der wert ist in Cent angegeben + * STUNDE heisst: er ist in Stunden angegeben + * (und das obwohl jedes Monat, Jahr unterschiedliche Stundenzahlen hat) + * PROZENT heisst er ist zwischen 0 und 100 angegeben (100%) + * NONE + **/ + class ZahlenWert { + ZahlenTyp zahlenTyp; + long wert; + } + + enum ZahlenTyp {EURO, STUNDE, PROZENT, NONE; } + + //---------------------------------------------- + //------------- Alerts ------------------------- + //---------------------------------------------- + + // Konto -> *MailAlert + + class MailAlert { + String name; + <> + String alertCondition; + <> + String mailBody; + int repetitions; + ZonedDateTime firstAlert; + ZonedDateTime lastAlert; + + Optional receipients; + Optional ccs; + Optional bccs; + + // extra Attribute zur Speicherung einiger Werte (vom System unbenutzt) + long a1; + long a2; + boolean flag1; + boolean flag2; + String s1; + String s2; + } + + //---------------------------------------------- + // ============ Finanz-Datenstruktur =========== + //---------------------------------------------- + + /** + * Hauptklasse; das Konto, von der alle anderen abhängen. + * Hat mehrere Varianten (Subklassen) + */ + abstract class Konto { + String name; + Optional pspElement; + Optional kontotyp; // unterschiedlich je nach Kontoart + Optional sapDatum; + Optional internesAktenzeichen; + boolean istPlanKonto; + boolean istVerbuchungsKonto; + boolean istAktiv; + Optional vergabeVerordnung; + Optional farbe; + Optional aenderungsdatum; + /Optional optStartDatum; + /Optional optEndDatum; + /Geschaeftsvorgang gueltigerGeschaeftsvorgang; + } + + <> + association [1] Konto (konto) -> (gesamtBudget) Budget [0..1]; + association [1] Konto -> (kommentare) Freitext [*]; + association [1] Konto -> (notiz) Freitext [0..1]; + association [1] Konto <-> MailAlert [*]; + association [1] Konto -> (abgleichsKonto) ExternKonto [0..1]; + + abstract class ErweitertesKonto extends Konto { + Optional startDatum; + Optional endDatum; + Optional bewilligungsDatum; // Bewilligungsdatum ist im Industrieprojekt nur mandatory, wenn kein Sammelkonto + Optional verlaengertBisDatum; + Optional aufstockungsDatum; + Optional foerderquote; + // human names: "Aktenzeichen (RWTH)" + // Drittmittel: "Förderkennzeichen", + Optional aktenzeichen; + Optional finanzierteKomplettsumme; + // human names: + // Drittmittel: "Aktenzeichen (Fördergeber)", + // Industrieprojekt: "Bestellnummer", + // Sonstiges: "Bestellnummer/Aktenzeichen (Fördergeber)" + Optional referenzSponsor; + boolean hatProgrammpauschale; + } + + + class Drittmittelprojekt extends ErweitertesKonto { + } + + association [*] Drittmittelprojekt -> (fachlicherVerantwortlicher) Person [*]; + + class Haushaltskonto extends Konto { + Optional startDatum; + Optional endDatum; + } + + class Industrieprojekt extends ErweitertesKonto { + Optional auftraggeber; + boolean istSammelkonto; + Optional mehrwertsteuer; + } + + association [*] Industrieprojekt -> (fachlicherVerantwortlicher) Person [*]; + + class Sonstiges extends ErweitertesKonto { + Optional auftraggeber; + Geschaeftsvorgang geschaeftsvorgang; + Optional mehrwertsteuer; + boolean istSammelkonto; + } + + + enum AbrechnungsInterval { + GESAMTE_PROJEKTLAUFZEIT("Gesamte Projektlaufzeit"), + JAEHRLICH("Jährlich"), + HALBJAEHRLICH("Halbjährlich"), + QUARTALSWEISE("Quartalsweise"), + MONATLICH("Monatlich"); + } + + association [1] Konto -> OrganigrammKonto [*]; + + class OrganigrammKonto { + Optional von; + Optional bis; + Optional umfang; + } + + association [*] OrganigrammKonto -> Organigramm [1]; + + class ZeitlicheVerbuchungskontoZuordnung { + Optional programmPauschale; + Optional gemeinkostensatz; + Optional startDate; + Optional endDate; + boolean istHauptVerbuchungskonto; + } + + association [1] ErweitertesKonto -> (verbuchungskontoZuordnung) ZeitlicheVerbuchungskontoZuordnung [*]; + association [*] ZeitlicheVerbuchungskontoZuordnung -> (verbuchungskonto) Konto [0..1]; + + //---------------------------------------------- + + // ------ Budget ------ + // Konto -> 1Budget + // Konto -> 1Budget -> *Budget + // Konto -> 1Budget -> *Budget -> *Budget + + /** + * Ein Budget erlaubt es ein Konto nach verschiedenen + * Strukturierungskriterien zu zerlegen. Budgets sind nur auf drei Ebenen + * erlaubt: 1 Hauptbudget, * OberBudgets, ** Unterbudgets. + * Die Budget-Struktur stellt einen Baum der maximalen Tiefe 3 dar. + */ + + class Budget { + String typ; // name + Optional startDatum; + Optional endDatum; + Optional kommentar; + Optional budgetRahmenCent; // wird im Gesamtbudget als Bewilligungssumme interpretiert + Optional eigenAnteilCent; + List jahresBudgets; + boolean proportionaleVerteilung; + boolean forOverheads; // das erste Budget (gesamtBudget.getUnterbudgets[0]) + Optional budgetKategorie; + /int budgetDepth; + } + + association [*] Budget -> Konto [1]; + association [0..1] Budget (elternBudget) <-> (unterBudget) Budget [*]; + association [1] Budget (budget) <-> (buchungseintrag) Buchungseintrag [*]; + association [1] Budget (budget) <-> (stellenzuweisung) Stellenzuweisung [*]; + <> + association [0..1] Budget -> Organigramm [0..1]; + + //---------------------------------------------- + + // ------ Buchungseinträge ------ + // Konto -> 1Budget (->*Budget)* -> *Buchung + + /** + * Buchungen aller Arten: gemeinsame Oberklasse + */ + abstract class Buchungseintrag { + ZonedDateTime datum; + Optional buchungseintragText; // human name: Buchung: "Buchungstext", Rechnung: "Rechnungsgrund", Mittelabruf: "Anmerkung", Mittelzuweisung: "Grund" + long betragCent; // human name: "Betrag", Rechnung: "Rechnungsbetrag", Konten mit Programmpauschale: "Rechnungsbetrag (inkl Pauschale)" + boolean istAktiv; + Optional aenderungsdatum; + /Geschaeftsvorgang gueltigerGeschaeftsvorgang; + /String lfdeNummer; + } + + class Buchung extends Buchungseintrag { + ZonedDateTime belegdatum; + String zahlungsgrund; //Belegpositionstext + Optional kreditorDebitor; + List sachkonto; + Optional buchungsdatum; + BuchungsStatus status; + List belegnummern; + List auftragsnummer; + Optional bereich; + Optional projekt; + Optional geschaeftsjahr; + Optional steuer; + Optional skonto; + Optional gez_Skonto; + Optional erfasser; + Optional belegart; + Optional referenz; + Optional stornonummer; + Optional stkz; + Optional erfassungsdatum; + Optional ausgleichsdatum; + long betragCentOriginal; // Bei Abweichungen von BetragCent kann nun eine Absicht ueberprueft werden + boolean budgetChangedManually; // s.o. + Optional kostenarten; + /Optional bezugsdatumJahr; + } + + class Rechnungsstellung extends Buchungseintrag { + Optional rechnungsdatum; + Optional rechnungsnummer; + RechnungsstellungStatus status; + List belegnummern; + Optional gemeinkosten; + Optional honorierung; + Optional projekt; + Optional debitor; + Optional mehrwertsteuer; + Optional zahlungsziel; + } + + class Mittelzuweisung extends Buchungseintrag { + Optional verfallDatum; + Optional kennung; + MittelzuweisungStatus status; + } + + class Mittelabruf extends Buchungseintrag { + ZonedDateTime abrufdatum; + MittelabrufStatus status; + String zeitraum; + Optional pauschaleManuell; // Präsent, falls die Pauschale manuell geändert wurde + } + + // ------ Stellenzuweisung ------ + + // Konto -> 1Budget (->*Budget)* -> *Stellenzuweisung + + class Stellenzuweisung { + ZonedDateTime erstellDatum; // aktuelles Datum + Optional startDatum; // Datum, zu welchem die Stelle beginnt + Optional endDatum; // Datum, zu welchem die Stelle endet + long wert; + String kennung; + StellenzuweisungStatus status; + ZahlenWert stellenumfang; + boolean istAktiv; + Optional aenderungsdatum; + } + + enum Geschaeftsvorgang { + NONE, + MITTELABRUF, + ZUWEISUNG, + RECHNUNG; + } + + enum BuchungsStatus { + EINGEREICHT, + SAP("SAP"), + SAP_STORNIERT("SAP(Storniert)"), + PLANUNG, + FEHLERHAFT; + } + + enum RechnungsstellungStatus { + OFFENE_RECHNUNG, + SAP("SAP"), + SAP_STORNIERT("SAP(Storniert)"), + PLANUNG; + } + + enum MittelzuweisungStatus { + BESCHEID_ERHALTEN ("Bescheid erhalten"), + SAP("SAP"), + SAP_STORNIERT("SAP(Storniert)"), + PLANUNG, + FEHLERHAFT; + } + + enum MittelabrufStatus { + ABGERUFEN, + SAP("SAP"), + SAP_STORNIERT("SAP(Storniert)"), + PLANUNG, + EINGEREICHT; + } + + enum StellenzuweisungStatus { + BESETZT, + TEILBESETZT, + UNBESETZT, + PLANUNG; + } + + enum VertragStatus { + AKTIV, + PLANUNG, + ABGELAUFEN; + } + + //---------------------------------------------- + // =============== SAPii =============== + //---------------------------------------------- + + class SAPVerbindung { + SAPverbindungsStatus status; + } + + class Anfrage { + String ikz; + String bezeichner; + boolean letzteAnfrageErfolgreich; + } + + enum SAPverbindungsStatus { + VERBUNDEN, + GETRENNT, + PROBLEM; + } + + enum SAPimportMode { + DEFAULT, + F1KONTO; + } + + association [1] SAPVerbindung -> (authorizedBy) MacocoUser [*]; + association [1] MacocoUser -> (anfragen) Anfrage [*]; + association [1] Anfrage -> (filteredKonten) PSPImportFilter [*]; + + //---------------------------------------------- + + class AbgleichsBuchung extends Buchung { + AbgleichsStatus abgleichsStatus; + Optional abgleichKommentar; + String positionsNummer; + boolean deactivated; + } + + enum AbgleichsStatus { + ABGESCHLOSSEN, // Der Abgleich dieser Buchung ist Abgeschlossen + TEILWEISE_ABGESCHLOSSEN, // Der Abgleich wurde schon Bearbeitet es fehlen jedoch Summen + ABWEICHEND, // Der Abgleich ist Vollständig mit Abweichenden Summen + OFFEN, // Der Abgleich wurde noch nicht gesetzt + VORGESCHLAGEN; // Der Abgleich wurde vom System vorgeschlagen + } + + class AbgleichsGruppe { + String bezeichnung; + } + <> + association AbgleichsGruppe -> (buchungen) Buchung [*]; + <> + association AbgleichsGruppe -> (abgleichsBuchungen) AbgleichsBuchung [*]; + <> + association AbgleichsGruppe -> (konto) Konto [1]; + + // ------ Freitext ------ + + class Freitext { + Optional erstellDatum; + Optional bearbeitetDatum; + <> + Optional text; + } + + class Legende { + LegendeTyp type; + String expression; + <> + String description; + } + + enum LegendeTyp { + KONTO_FARBE; + } + + //---------------------------------------------- + // =============== Projekte =============== + //---------------------------------------------- + + abstract class Projekt { + String name; + String kuerzel; + Optional minPM; + Optional maxPM; + Optional finanzPM; + Optional laufzeitVon; + Optional laufzeitBis; + Optional kommentar; + Optional foerdergeberAZ; + ProjektStatus status; + boolean istAktiv; + boolean lockedForStundenzettel; // Das gesamte Projekt ist gesperrt + List lockedMonths; // Stellen die Ausnahme aus der Lock-Regelung für das gesamte Projekt dar + Optional aenderungsdatum; + } + + association [1] Projekt -> Aufwand [*]; + association [1] Projekt -> Arbeitspaket [*]; + association [1] Projekt -> Anstellung [*]; + association [*] Projekt -> Konto [0..1]; + association [*] Projekt -> (hauptverantwortlich) Person [*]; + association [1] Projekt -> (notiz) Freitext [0..1]; + + class Auftragsprojekt extends Projekt { + Optional nummer; + ProjektTyp typ; + Optional regelung; + } + + class Organisation extends Projekt { + } + + class Lehre extends Projekt { + Optional stunden; + } + + class Arbeitspaket { + String nummer; // könnte auch 1.1 sein + String name; + Optional beschreibung; + Optional beginnDatum; + Optional endeDatum; + Optional pMs; + Optional stunden; + Optional aenderungsdatum; + } + + class Aufwand { + /long pM; + ZahlenWert umfang; + ZonedDateTime laufzeitVon; + ZonedDateTime laufzeitBis; + Optional aenderungsdatum; + } + + association [*] Aufwand -> Person [0..1]; + + class Anstellung { + Optional bezeichnung; + ZahlenWert umfang; + ZonedDateTime von; + ZonedDateTime bis; + boolean verfaellt; + Optional min; + Optional max; + /long pM; + BeschaeftigungsArt beschaeftigungsArt; + } + + association [*] Anstellung -> Person [0..1]; + + class Stellentyp { + Optional entgeltgruppe; + Optional entgeltstufe; + } + + enum ProjektStatus { + IN_DEFINITION, + BEANTRAGT, + GENEHMIGT, + ABGELEHNT, + LAUFEND, + FACHLICH_ABGESCHLOSSEN("Fachlich abgeschlossen"), + ENDBERICHT_EINGEREICHT("Endbericht eingereicht"), + INPRUEFUNG("In Prüfung"), + GEPRUEFT("Geprüft"), + ABGERECHNET, + ABGESCHLOSSEN, + ARCHIVIERT; + } + + enum ProjektArt { + AUFTRAG, + ORGANISATION, + LEHRE, + NONE; + } + + enum ProjektTyp { + HOHEITLICH, + INDUSTRIE, + UNIVERSITAET("Universität"), + SONSTIGE; + } + + enum Vergabeverordnung { + VOL_A ("VOL/A"), + VOB_A ("VOB/A"), + UVGO_NRW ("UVgO NRW"), + UVGO_BUND ("UVgO Bund"), + NONE (" "); + } + + //---------------------------------------------- + // =============== Stundenzettel =============== + //---------------------------------------------- + + class Stundenzettel { + StundenzettelStatus status; + ZonedDateTime zeit; + Optional abgegebenVonUserId; + Optional abgabeDatum; + } + + association [1] Stundenzettel -> (eintraege) StundenzettelEintrag [*]; + + class StundenzettelEintrag { + ZonedDateTime uhrzeitVon; + Optional uhrzeitBis; + Optional beschreibung; + /long stunden; + StundenzettelProjekt pauseOderSonstiges; + } + + association [*] StundenzettelEintrag -> Projekt [0..1]; + association [*] StundenzettelEintrag -> Arbeitspaket [0..1]; + + class StundenzettelHistorieEintrag { + ZonedDateTime bearbeitungsdatum; + Optional editorId; + Optional editedBy; + String monat; + int jahr; + String changeOperation; + } + + enum StundenzettelChangeOperation { + INVALID, + ABGEGEBEN("Abgegeben"), + INTERN_GEPRUEFT("Intern Geprüft"), + INTERN_ABGESCHLOSSEN("Intern Abgeschlossen"); + } + + association [1] Person -> StundenzettelHistorieEintrag [*]; + + class Abwesenheit { + Abwesenheitsgrund grund; + ZonedDateTime datumVon; + ZonedDateTime datumBis; + Optional kommentar; + Optional uhrzeitVon; + Optional uhrzeitBis; + Optional minutenProTag; + /long tageGesamt; + } + + class Dienstreise extends Abwesenheit { + Optional reisenummer; + Optional dienstreisegrund; + Optional reiseziel; + Optional gesamtkosten; + Optional status; + Optional statusText; + } + + association [*] Abwesenheit -> Konto [0..1]; + + association [1] Abwesenheit -> UrlaubsGenehmigung [0..1]; + + association [*] Dienstreise -> Budget [0..1]; + + class Arbeitstage { + ZonedDateTime guiltigAb; + ZonedDateTime guiltigBis; + List wochenTage; // 0..4 (Montag-Freitag) + } + + association [1] Person -> Arbeitstage [*]; + + class Jahresurlaub { + int jahr; + long tageAnzahl; + Optional stundenAnzahl; + boolean istManuellerEintrag; + } + + class UrlaubsGenehmigung { + Optional beantragt; + Optional genehmigt; + Optional geprueft; + Optional storniert; + Urlaubssstatus status; + Stornierungsstatus stornierungsStatus; + } + + class Sonderurlaub { // Für WZL: Zusatzurlaub umbenennen in Sonderurlaub und neues Feld anzahl + ZonedDateTime datumVon; + ZonedDateTime datumBis; + long anzahl; + } + + class UrlaubEinstellungen { + boolean urlaubsanspruchInStunden; + } + + enum Abwesenheitsgrund { + U_URLAUB, + D_DIENSTREISE, + S_SONSTIGE; + /* + Z_ZUSATZURLAUB, + A_ARBEITSUNFALL, + AB_ABGELTUNG, + E_ELTERNZEIT, + F_FREISTELLUNG, + K_KRANKHEIT, + KU_KUR, + S_SONSTIGES;*/ + } + + enum Urlaubssstatus { + NONE, + BEANTRAGT, + GEPRUEFT("Geprüft"), + PRUEFUNG_ABGELEHNT("Prüfung abgelehnt"), + GENEHMIGT, + GENEHMIGUNG_ABGELEHNT; + } + + enum Stornierungsstatus { + NONE, + VERBOTEN, + STORNIERUNGSANTRAG, + STORNIERT; + } + + enum Abrechnungsstatus { + OFFEN, + ABZURECHNEN, + ABGERECHNET, + STORNIERT; + } + + enum StundenzettelStatus { + IN_ERFASSUNG, + INTERN_INPRUEFUNG("Intern in Prüfung"), + INTERN_ABGESCHLOSSEN, + DRITTMITTELABTEILUNG_INPRUEFUNG("Drittmittelabteilung in Prüfung"), + DRITTMITTELABTEILUNG_ABGESCHLOSSEN, + ENDBERICHT_EINGEREICHT, + GEPRUEFT("Geprüft"), + FOERDERGEBER_ABGESCHLOSSEN("Fördergeber abgeschlossen"), + ABGESCHLOSSEN; + } + + enum StundenzettelProjekt { + PAUSE, + SONSTIGE, + NONE; + } + + association [*] F1Konto -> (institut) Institut [0..1]; + + class ExternKonto extends Konto { + Optional startDatum; + Optional endDatum; + Optional importVermerk; + AbgleichType abgleichVerhalten; + } + + enum AbgleichType { + IGNORE, + MANUEL, + AUTO_COPY; + } + + association [*] ExternKonto -> (institut) Institut [0..1]; + + class PSPImportFilter{ + boolean importThisPSPelement; + boolean importBookings; + String name; + String pspElement; + Optional startDate; + } + + association [*] PSPImportFilter -> (targetPSP) Konto [0..1]; + + //---------------------------------------------- + // Reports + + class EventReport { + ZonedDateTime eventStart; + Optional eventEnd; + /EventStatus status; + String message; // BuchungImport: Nutzer 'netz' hat die Datei '.....' importiert + } + + class EventReportEntry { + EventType type; + Optional targetId; // click -> navigate to id + Optional count; + <> + String message; // Zeile 4 Fehler ...... Zeile 5 ..... + EventStatus status; + } + association [1] EventReport -> (entries) EventReportEntry [*]; + + class ImportReport extends EventReport { + } + + class ImportReportEntry extends EventReportEntry { + } + + + class PersonalExportReport extends EventReport { + Long dataId; + + ZonedDateTime datenStart; + ZonedDateTime datenEnd; + Long countData; + /Long countError; + EventStatus exportStatus; + } + + class PersonalExportReportEntry extends EventReportEntry { + Optional vorsatzwort; + String vorname; + String nachname; + BeschaeftigungsArt beschaeftigungsArt; + ZonedDateTime monat; + } + + enum EventStatus { + // Import + SUCCESS("erfolgreich"), + ERROR("fehlerhaft"), + INFO("erfolgreich"), // success + special + CREATED("erstellt"), + UPDATED("upgedated"), + IGNORED("ignoriert"), + IN_PROGRESS("in bearbeitung"), + + // Personal Export + SENT("verschickt"), + CORRECT("sachlich korrekt"); + } + + enum EventType { + IMPORT_KONTO("Konten"), + IMPORT_BUCHUNG("Buchungs"), + IMPORT_PERSON("Personen"), + IMPORT_INSTITUT("Instituts"), + IMPORT_NUTZER("Nutzer"), + IMPORT_VERTRAG("Vertrags"), + EXPORT_FINANZEN_KONTO("Konten"), + EXPORT_FINANZEN_PLANSTELLE("Planstellen"), + EXPORT_FINANZEN_VERTRAG("Vertragabdeckungs"); + } + + + //---------------------------------------------- + // =============== Fakultät 1 DS =============== + //---------------------------------------------- + + // Institut + <> + class Institut { + String institutsKennZiffer; + String institutsName; + String professorName; + boolean lokalInstitut; + } + + // Fachgruppe + enum Fachgruppe { + MATHEMATIK, + INFORMATIK, + PHYSIK, + CHEMIE, + BIOLOGIE; + } + + //SAP-Abschöpfung von Geschäftsjahr + class GeschaeftsjahrSAPAbschoepfung { + String fachgruppe; + String institutsKennZiffer; + String institutsName; + String pspElement; + long gesamtSAPAbschoepfung; + } + + class SAPAbschoepfung { + Long betragCent; + ZonedDateTime year; + } + + association [1] GeschaeftsjahrSAPAbschoepfung -> (sapAbschoepfung) SAPAbschoepfung [*]; + + + // Konto + class F1Konto extends Haushaltskonto { + long originalBudgetCent; + long sonstigeZuweisungenCent; + long resteCent; + long aktuellerKontostandCent; + long kontoRahmenCent; + KommunikationsStatus kommunikationsStatus; + StrafsteuerStatus strafsteuerStatus; + long strafsteuerBasisCent; + long strafsteuerSAPCent; + long strafsteuerCent; + long strafsteuerBerechnungsGrundlageCent; + Optional kontoStandBeginnGeschaeftsjahr; + } + + // Konto -> 1Budget (->*Budget)* -> *Buchung -> ?Begruendung + + // Buchungen werden hier noch erweitert: + association [1] Buchung -> (begruendung) Begruendung [0..1]; + + class Begruendung { + String text; + ZonedDateTime erstellung; + Optional letzteBearbeitung; + Optional geschaeftsjahr; + } + + association [1] Begruendung -> (akzeptanz) Akzeptanz [0..1]; + //association [1] Begruendung -> (geschaeftsjahr) StrafsteuerGeschaeftsjahr [0..1]; + + //---------------------------------------------- + + // Konto -> 1Budget (->*Budget)* -> *Buchung -> ?Begruendung -> ?Akzeptanz + + class Akzeptanz { + Akzeptanzstatus akzeptanzstatus; + Optional teilbetragCent; + Optional bearbeitung; + boolean istAktiv; + Optional kommentar; + } + + //---------------------------------------------- + + enum KommunikationsStatus { + KOM_STAT_NO_ACTION_NEEDED, // Kein Handlungsbedarf + KOM_STAT_BEGR_FEHLT, // Begründung fehlt + KOM_STAT_ANTW_FEHLT, // Antwort fehlt + KOM_STAT_ANTW_CHANGED, // Buchung oder Begründung wurden geändert + KOM_STAT_BEGR_CHANGED, // Antwort wurde geändert + KOM_STAT_ANTW_BEGR_CHANGED, // Antwort und Begründung wurde geändert + KOM_STAT_ANTW_FEHLT_CHANGED; // Antwort Fehlt, andere Antwort wurde geändert + } + + enum StrafsteuerStatus { + NONE, + SOME, + ALL; + } + + enum Akzeptanzstatus { + OFFEN, + OK, + TEILOK, + NOTOK; + } + + class StrafsteuerGeschaeftsjahr { + ZonedDateTime jahr; + boolean current; + } + + class StrafsteuerSperrDatum { + ZonedDateTime sperrDatum; + } + + //---------------------------------------------- + // =============== MacocoUser =============== + //---------------------------------------------- + + class MacocoUser { + <> + String username; + Optional encodedPassword; + String passwordSaltBase64; + ZonedDateTime registrationDate; + Optional initials; + MacocoUserActivationStatus activated; + boolean enabled; + <> + String email; + boolean authentifiziert; + Optional timID; + Optional sapAccessToken; + Optional sapRefreshToKen; + + } + + association [*] MacocoUser -> (institute) Institut [*]; + + enum MacocoUserActivationStatus { + AKTIVIERT, + MAIL_NICHT_GESENDET("Mail nicht gesendet"), + MAIL_FEHLERHAFT("Mail fehlerhaft"), + MAIL_GESENDET("Mail gesendet"); + } + + // Favoriten + class Favorite { + String title; + String url; + } + + association [1] MacocoUser -> (favorite) Favorite [*]; + + class RoleAssignment { + } + + association [*] RoleAssignment -> (user) MacocoUser [1]; + association [*] RoleAssignment -> (accessPolicy) AccessPolicy [1]; + + class AccessPolicy { + String roleName; + Optional objId; + } + + class GroupedAccessPolicy { + String name; + } + + association [*] GroupedAccessPolicy -> (user) MacocoUser [*]; + association [1] GroupedAccessPolicy -> (policy) AccessPolicy [*]; + + //---------------------------------------------- + // =============== Fristen =============== + //---------------------------------------------- + + class Frist { + String beschreibung; + Friststatus status; + Fristobjekt fristobjekt; + ZonedDateTime faelligkeitsdatum; + Optional notiz; + Boolean manuellerEintrag; + Long bezugsobjektId; + String bezugsobjektName; + Optional aenderungsdatum; + boolean istAktiv; + } + + association [*] Frist -> (zuweisung) Person [0..1]; + + association [1] Person -> Frist [*]; + association [1] Konto -> Frist [*]; + association [1] Projekt -> Frist [*]; + association [1] Mittelabruf -> Frist [0..1]; + association [1] Rechnungsstellung -> Frist [0..1]; + association [1] Vertrag -> Frist [0..1]; + association [1] Zulage -> Frist [0..1]; + + enum Friststatus { + PLANUNG, + IN_BEARBEITUNG, + ERLEDIGT; + } + + enum Fristobjekt { + PERSON, + KONTO, + VERTRAGSVERLAENGERUNG("Vertragsverlängerung"), + ZULAGE, + RECHNUNG, + MITTELABRUF, + PROJEKT; + } + + class DefaultFristen { + ZonedDateTime finanzenStartDatum; + Long finanzenFristinWeeks; + ZonedDateTime personalStartDatum; + Long personalFristinWeeks; + } + + //---------------------------------------------- + // ============= Einstellungen ================= + //---------------------------------------------- + + class Setting { + String identifier; + } + + class InstanzSetting extends Setting { + String value; + } + + class UISetting extends Setting { + String seite; + } + + association [0..1] MacocoUser -> (setting) UISetting [*]; + + class FilterSetting extends UISetting { + List filterValues; + } + + class TableSetting extends UISetting { + TableIdentifierTyp typ; + boolean zeigeInaktive; + int zeilenLimit; + Optional gruppiereNach; + Optional sortiereNach; + Optional sortiereDir; + boolean isShowColor; + } + + association [1] TableSetting -> (spalten) TableSettingSpalten [*]; + + enum TableIdentifierTyp { + DEFAULT, + USER, + INSTITUT; + } + + class TableSettingSpalten { + String name; + boolean istAktiv; + long breite; + } + + class ErweiterbareListen{ + String bereich; + String feldbezeichnung; + List inhalte; + } + + //---------------------------------------------- + // =============== Card Settings =============== + //---------------------------------------------- + + class CardSetting { + String page; + String identifier; + <> + String configuration; + } + + association [*] CardSetting -> (benutzer) MacocoUser [0..1]; + + //---------------------------------------------- + // =============== WZL =============== + //---------------------------------------------- + + class Elternzeit { // WZL + Optional von; + Optional bis; + ZahlenWert umfang; + } + + class Nebentaetigkeit { // WZL + Optional von; + Optional bis; + ZahlenWert umfang; + Optional arbeitgeber; + Optional taetigkeitsbereich; + } + + class Zulage { // WZL + Optional pspelement; + Optional bezeichnung; + ZonedDateTime von; + ZonedDateTime bis; + Long arbeitgeberbrutto; + Long arbeitnehmerbrutto; + } + + // WZL + enum Geschlecht { NONE(""), WEIBLICH("weiblich"), MAENNLICH("männlich"), DIVERS("divers"); } + + // WZL + // -> DataSource + enum Titel { NONE(""), E1("Apl. Prof. Dr.") , E2("B.Sc.") , E3("Dipl.-Inform.") , E4("Dipl.-Ing."), E5("Dipl.-Ing. (FH)"), + E6("Dipl.-Ing. (RUS)"), E7("Dipl.-Kff.") , E8("Dipl.-Math."), E9("Dipl.-Phys.") , E10("Dipl.-Wirt. Ing.") , E11("Dr.") , E12("Dr. phil."), + E13("Dr. rer. nat."), E14("Dr. rer. pol."), E15("Dr.-Ing."), E16("M.A.") , E17("M.Eng."), E18("M.Sc."), E19("PhD"), E20("Prof. Dr.-Ing."); } + + // WZL + // -> DataSource + enum Berufsgruppe { NONE(""), E1("Akademischer Direktor"), E2("Angestellter in der DV"), E3("Auszubildende/r"), E4("Bibl.-Beschäftiger"), + E5("Elektriker"), E6("Elektroniker"), E7("Elektrotechniker"), E8("Fachinformatiker"), E9("Fachinformatiker"), E10("Industriemechaniker"), + E11("Lagerarbeiter"), E12("Mechaniker"), E13("Meister"), E14("Praktikant, SV-frei"), E15("Programmierer"), E16("Stud. Hilfskraft"), + E17("Techn. Beschäftigter"), E18("Techn. Zeichner"), E19("Techniker"), E20("Universitätsprofessor"), E21("Verw. Beschäftigter"), E22("Werkstoffprüfer"), + E23("Wiss. Beschäftigter"), E24("Wiss. Hilfskraft Bachelor"), E25("Wiss. Hilfskraft Master"); } + + // WZL + enum Aktion { NONE(""), ANFRAGE_VERSENDET("Anfrage versendet"), ERINNERUNG_VERSENDET("Erinnerung versendet"), + ZUR_UNTERSCHRIFT_BEIM_VORGESETZTEN("Zur Unterschrift beim Vorgesetzten"), + BEI_ZHV_VORGELEGT("Bei ZHV vorgelegt"), VON_ZHV_BESTAETIGT("Von ZHV bestätigt"); } + + // WZL + // -> DataSource + enum Vertragsgrundlage { NONE(""), E1("sonst. Befristungen (gleicht Auszubildenden)"), E2("unbefristet"), E3("unbefr. (Beamter aL)"), E4("§14 Abs. 2 TzBfG"), + E5("Elternzeitvertretung"), E6("Befristung SHK"), E7("Mehrbedarf sonstiger"), E8("Mehrb. Forschungspr."), E9("§2(5)Nr.3WZVG MuS-EZ"), + E10("§2 WZVG DM (NP)"), E11("§2 WZVG KiBetr NP"), E12("WZVG-Postdoc-Quali."), E13("WZVG-N-Gr._Leiter"), E14("WZVG-Wiss.-Quali NP"), + E15("§2 WZVG DM (VP)"), E16("§2 WZVG KiBetr VP"), E17("WZVG-Promotion"), E18("WZVG-sonst.Wiss-Qual"), E19("Befristung WHB"), E20("Befristung WHK"), + E21("§2 (1) S.2 WZVG nPr"), E22("§14(1) Nr.2 TzBfG-Üb"), E23("befr. Arbeitszeitänderung"), E24("Übernahme nach Ausbildung"); } + + association [1] Person -> (elternzeiten) Elternzeit [*]; // WZL + association [1] Person -> (nebentaetigkeiten) Nebentaetigkeit[*]; // WZL + association [1] Person -> (zulagen) Zulage [*]; // WZL + + // WZL Personal Export + class PersonalExportData { + } + association [1] PersonalExportData -> (entries) PersonalExportDataEntry [*]; + + class PersonalExportDataEntry { + String personalnummer; + Optional vorsatzwort; + String nachname; + String vorname; + ZonedDateTime von; + ZonedDateTime bis; + String pspElement; + Long prozentsatz; + } + + class PersonalExportEinstellungen { + String pspElement; + List bezeichnungen; + ZonedDateTime startmonat; + ZonedDateTime endmonat; + } + + class Organigramm { + boolean istStabstelle; + boolean istAktiv; + String bezeichnung; + } + + <> + association [0..1] Organigramm (parent) <-> (child) Organigramm [*]; + + association [1] Organigramm -> (leiter) OrganigrammPersonInfo [*]; + association [1] Organigramm -> (stellvertreter) OrganigrammPersonInfo [*]; + association [1] Organigramm -> (mitarbeiter) OrganigrammPersonInfo [*]; + + class OrganigrammPersonInfo { + Optional von; + Optional bis; + Optional umfang; + } + + association [*] OrganigrammPersonInfo -> Person [1]; + + //---------------------------------------------- + // =============== WZL END =============== + //---------------------------------------------- + + + // Druckeinstellungen + class DruckEinstellungenProjekt { + Long projektId; + Integer jahr; + Integer monat; + Optional mittelabrufnummer; + Optional belegnummer; + } + + association [1] DruckEinstellungenProjekt -> (druckEinstellungenPersonen) DruckEinstellungenPerson [*]; + + class DruckEinstellungenPerson { + Long personId; + Optional stundensatz; + } + + class BlacklistedToken { + <> // have more than 255 characters + String token; + ZonedDateTime addedAt; + ZonedDateTime expiresAt; + } + + class RefreshToken { + long userId; + String token; + } + + // NotificationCenter + class UserNotification { + UserNotificationType notificationType; + String title; + + <> + String message; + ZonedDateTime timeStamp; + + // clickable + Optional link; // fuer Router + + boolean seen; + boolean pinned; + } + + enum UserNotificationType { SUCCESS, INFO, WARNING, DANGER; } + + association [1] MacocoUser -> (notification) UserNotification [*]; + + //---------------------------------------------- + // =============== Command Logs ================ + //---------------------------------------------- + class AccessIdentifier { + } + + class CommandLog { + ZonedDateTime timestamp; + List diff; + String affectedArea; + String affectedObject; + } + + association [1] CommandLog -> (executor) MacocoUser [0..1]; // TODO: In den Migrationsskript für 2.9.0 -> 2.10.0 : früher war association [1] CommandLog -> (executor) MacocoUser [1]; + association [1] CommandLog -> (permission) AccessIdentifier [*]; + + //---------------------------------------------- + // =============== Dokumente =================== + //---------------------------------------------- + + // Bei Änderung PermissionCheckHelper.doesUserHavePermissionForDokument updaten + enum DokumentGroup { + PERSONAL("personal"), + KONTO("konto"); + } + + class Dokument { + DokumentGroup groupName; + Long associationId; // ID des Objektes an dem das Dokument hängt + ZonedDateTime datum; // Upload-Datum + String bezeichnung; + String dateiFormat; + Long fileSize; + Optional anmerkung; + boolean istAktiv; + } + +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/MaCoCoRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/MaCoCoRef.cd new file mode 100644 index 00000000..ea32f1f3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/MaCoCoRef.cd @@ -0,0 +1,1456 @@ +/* (c) https://github.com/MontiCore/monticore */ +/* adapted and customized by (c) MaCoCo, ein RWTH Aachen projekt */ + +// No packages supported yet in CD completion! +//package de.macoco.be.domain; + +import java.lang.String; +import java.lang.Long; +import java.lang.Integer; +import java.lang.Boolean; +import java.util.List; +import java.util.Optional; +import java.time.ZonedDateTime; + +classdiagram MaCoCo { + + //---------------------------------------------- + //--------------- PERSONAL --------------------- + //---------------------------------------------- + + /** + * Person ist die Zentrale Klasse des Personal-Komplexes. + **/ + class Person { + String vorname; + Optional vorsatzwort; + String nachname; + String kuerzel; // Abgeleitet analog wie bei SAP: 3 Vor- 3 Nachnamenbuchstaben + Optional personalnummer; + Optional gebDatum; + Optional beschBeginn; + Optional beschEnde; + List kommentar; + boolean istAktiv; + boolean istStundenzettelpflichtig = false; + Optional stundenzettelpflichtigVon; + Optional stundenzettelpflichtigBis; // TODO: brauchen wir nicht mehr + Optional ueberStundenUebertrag; + boolean darfWochenendarbeiten; + // Start WZL: + Optional hoechstbeschaeftigungBis; + List staatsangehoerigkeiten; + Optional telefonnummer; + Optional arbeitserlaubnisBis; + boolean extern; + Optional titel; + Optional rufname; + Optional adresse; + Optional email; + Optional geburtsname; + Optional geschlecht; + Optional lBVNummer; + Optional entfristung; + <> + Optional qualifikationstitel; + boolean speicherungGewuenscht = false; + <> + Optional urlaubskommentar; + Optional aenderungsdatum; + } + + association [1] Person -> (anstellungsarten) Anstellungsart [*]; + association [*] Person -> (vorgesetzte) Person [*]; + association [1] Person -> (notiz) Freitext [0..1]; + + //Für Studentenzettel: + association [1] Person -> (jahresurlaubstage) Jahresurlaub [*]; + association [1] Person -> (zusatzurlaubstage) Sonderurlaub [*]; + association [1] Person -> (stundenzettel) Stundenzettel [*]; + association [1] Person -> (abwesenheiten) Abwesenheit [*]; + + <> + association [1] Person -> (user) MacocoUser [0..1]; + + + //---------------------------------------------- + // Person -> *Anstellungsart + + class Anstellungsart { + BeschaeftigungsArt beschArt; + } + + association [1] Anstellungsart -> (vertraege) Vertrag [*]; + association [1] Anstellungsart -> (anstellungsformen) Anstellungsform [*]; + + enum BeschaeftigungsArt { + WiMi("Wissenschaftliche/r Mitarbeiter/in (WiMi)"), + HiWi("Hilfskraft (HiWi)"), + BTV("Beschäftigte/r in Technik und Verwaltung (BTV)"), + BEAMTE("Beamte/r"), + AZUBI("Azubi/ne"), + PLAN; + } + + //---------------------------------------------- + // Person -> *Anstellungsart -> *Vertrag + // eine direkte Verbindung zwischen Person und Vertrag existiert nicht. + + class Vertrag { // spiegelt den Vertrag der Hochschule wieder + ZonedDateTime vertragsBeginn; + ZonedDateTime vertragsEnde; + boolean aenderungsvertrag; + /String vertragsStatus; // Aktiv, Planung, Abgelaufen // TODO: change String to enum + List kommentar; + ZahlenWert planUmfang; + Optional arbeitsstundenProWoche; //Stundenzettel + boolean kuendigungsschutz; // WZL + Optional vertragsgrundlage; // WZL / TODO: change to enum + Optional aktion; // WZL / TODO: change to enum + Optional aktionsDatum; // WZL / TODO: change to enum + } + + association [1] Vertrag -> (kostenstellen) Kostenstelle [*]; + + //---------------------------------------------- + // Person -> *Anstellungsart -> Anstellungsform + + /** + * Beschreibt alle wesentlichen Merkmale einer Anstellung. + * Entgeltgruppe, Stufe, etc. + **/ + class Anstellungsform { + boolean erstanstellung; + Optional entgeltGruppe; // { TVL-13} Für Hiwis: {SHK (default), WHB, WHK} + Optional erfahrungsStufe; // 1- 6 ; sowie Spezialfälle (TVL Ü+); + boolean unbefristet; + ZonedDateTime anstellungVon; + Optional anstellungBis; + long gehaltCent; // evtl. Schätzgehalt in Zukunft + boolean istEigenerReferenzwert; + List kommentar; + Optional berufsgruppe; // WZL / TODO: change to enum + Optional aktion; // WZL / TODO: change to enum + Optional aktionsDatum; // WZL / TODO: change to enum + } + + //---------------------------------------------- + // Person -> *Anstellungsart -> *Vertrag -> *Kostenstelle + + class Kostenstelle { + ZonedDateTime verbuchungsBeginn; + ZonedDateTime verbuchungsEnde; + KostenstelleBezeichnung bezeichnung; + List kommentar; + ZahlenWert beschaeftigungsUmfang; + boolean buchungenNeuErzeugen; + boolean buchungenLoeschen; + boolean gesperrt; + } + + enum KostenstelleBezeichnung { + NONE(""), + AN_INSTITUT("An-Institut"), + GMBH("GmbH"), + ANDERER_LEHRSTUHL, + ANDERES_INSTITUT, + VORUEBERGEHEND_ABWESEND("Vorübergehend Abwesend"), + ANDERE_FINANZIERUNG; + } + + enum Zuweisungsart { + KONTO("Kontenzuweisung"), + STELLENZUWEISUNG, + PLANSTELLE, + SONSTIGES; + } + + association [*] Kostenstelle -> (personalBudget) Budget [0..1]; + association Kostenstelle -> (stellenzuweisung) Stellenzuweisung [0..1]; + association Kostenstelle -> (planstelle) Planstelle [0..1]; + <> + association [0..1] Kostenstelle -> (personalBuchungen) Buchung [*]; + + // Person -> *Anstellungsart -> *Vertrag -> *Kostenstelle -> ?Planstelle + + class Planstelle { + String bezeichnung; + Optional minEntgeltgruppe; + Optional minEntgeltstufe; + Optional maxEntgeltgruppe; + Optional maxEntgeltstufe; + Optional verfuegbarVon; + Optional verfuegbarBis; + Optional kommentar; + ZahlenWert planUmfang; + boolean aktiv; + } + + association Planstelle -> (konto) Konto [0..1]; + + //---------------------------------------------- + + /** + * Repräsentiert verschiedene Arten von monetären Haben + * @attribute wert ist jeweils unterschiedlich zu interpretieren: + * EURO heisst, der wert ist in Cent angegeben + * STUNDE heisst: er ist in Stunden angegeben + * (und das obwohl jedes Monat, Jahr unterschiedliche Stundenzahlen hat) + * PROZENT heisst er ist zwischen 0 und 100 angegeben (100%) + * NONE + **/ + class ZahlenWert { + ZahlenTyp zahlenTyp; + long wert; + } + + enum ZahlenTyp {EURO, STUNDE, PROZENT, NONE; } + + //---------------------------------------------- + //------------- Alerts ------------------------- + //---------------------------------------------- + + // Konto -> *MailAlert + + class MailAlert { + String name; + <> + String alertCondition; + <> + String mailBody; + int repetitions; + ZonedDateTime firstAlert; + ZonedDateTime lastAlert; + + Optional receipients; + Optional ccs; + Optional bccs; + + // extra Attribute zur Speicherung einiger Werte (vom System unbenutzt) + long a1; + long a2; + boolean flag1; + boolean flag2; + String s1; + String s2; + } + + //---------------------------------------------- + // ============ Finanz-Datenstruktur =========== + //---------------------------------------------- + + /** + * Hauptklasse; das Konto, von der alle anderen abhängen. + * Hat mehrere Varianten (Subklassen) + */ + abstract class Konto { + String name; + Optional pspElement; + Optional kontotyp; // unterschiedlich je nach Kontoart + Optional sapDatum; + Optional internesAktenzeichen; + boolean istPlanKonto; + boolean istVerbuchungsKonto; + boolean istAktiv; + Optional vergabeVerordnung; + Optional farbe; + Optional aenderungsdatum; + /Optional optStartDatum; + /Optional optEndDatum; + /Geschaeftsvorgang gueltigerGeschaeftsvorgang; + } + + <> + association [1] Konto (konto) -> (gesamtBudget) Budget [0..1]; + association [1] Konto -> (kommentare) Freitext [*]; + association [1] Konto -> (notiz) Freitext [0..1]; + association [1] Konto <-> MailAlert [*]; + association [1] Konto -> (abgleichsKonto) ExternKonto [0..1]; + + abstract class ErweitertesKonto extends Konto { + Optional startDatum; + Optional endDatum; + Optional bewilligungsDatum; // Bewilligungsdatum ist im Industrieprojekt nur mandatory, wenn kein Sammelkonto + Optional verlaengertBisDatum; + Optional aufstockungsDatum; + Optional foerderquote; + // human names: "Aktenzeichen (RWTH)" + // Drittmittel: "Förderkennzeichen", + Optional aktenzeichen; + Optional finanzierteKomplettsumme; + // human names: + // Drittmittel: "Aktenzeichen (Fördergeber)", + // Industrieprojekt: "Bestellnummer", + // Sonstiges: "Bestellnummer/Aktenzeichen (Fördergeber)" + Optional referenzSponsor; + boolean hatProgrammpauschale; + } + + + class Drittmittelprojekt extends ErweitertesKonto { + } + + association [*] Drittmittelprojekt -> (fachlicherVerantwortlicher) Person [*]; + + class Haushaltskonto extends Konto { + Optional startDatum; + Optional endDatum; + } + + class Industrieprojekt extends ErweitertesKonto { + Optional auftraggeber; + boolean istSammelkonto; + Optional mehrwertsteuer; + } + + association [*] Industrieprojekt -> (fachlicherVerantwortlicher) Person [*]; + + class Sonstiges extends ErweitertesKonto { + Optional auftraggeber; + Geschaeftsvorgang geschaeftsvorgang; + Optional mehrwertsteuer; + boolean istSammelkonto; + } + + + enum AbrechnungsInterval { + GESAMTE_PROJEKTLAUFZEIT("Gesamte Projektlaufzeit"), + JAEHRLICH("Jährlich"), + HALBJAEHRLICH("Halbjährlich"), + QUARTALSWEISE("Quartalsweise"), + MONATLICH("Monatlich"); + } + + association [1] Konto -> OrganigrammKonto [*]; + + class OrganigrammKonto { + Optional von; + Optional bis; + Optional umfang; + } + + association [*] OrganigrammKonto -> Organigramm [1]; + + class ZeitlicheVerbuchungskontoZuordnung { + Optional programmPauschale; + Optional gemeinkostensatz; + Optional startDate; + Optional endDate; + boolean istHauptVerbuchungskonto; + } + + association [1] ErweitertesKonto -> (verbuchungskontoZuordnung) ZeitlicheVerbuchungskontoZuordnung [*]; + association [*] ZeitlicheVerbuchungskontoZuordnung -> (verbuchungskonto) Konto [0..1]; + + //---------------------------------------------- + + // ------ Budget ------ + // Konto -> 1Budget + // Konto -> 1Budget -> *Budget + // Konto -> 1Budget -> *Budget -> *Budget + + /** + * Ein Budget erlaubt es ein Konto nach verschiedenen + * Strukturierungskriterien zu zerlegen. Budgets sind nur auf drei Ebenen + * erlaubt: 1 Hauptbudget, * OberBudgets, ** Unterbudgets. + * Die Budget-Struktur stellt einen Baum der maximalen Tiefe 3 dar. + */ + + class Budget { + String typ; // name + Optional startDatum; + Optional endDatum; + Optional kommentar; + Optional budgetRahmenCent; // wird im Gesamtbudget als Bewilligungssumme interpretiert + Optional eigenAnteilCent; + List jahresBudgets; + boolean proportionaleVerteilung; + boolean forOverheads; // das erste Budget (gesamtBudget.getUnterbudgets[0]) + Optional budgetKategorie; + /int budgetDepth; + } + + association [*] Budget -> Konto [1]; + association [0..1] Budget (elternBudget) <-> (unterBudget) Budget [*]; + association [1] Budget (budget) <-> (buchungseintrag) Buchungseintrag [*]; + association [1] Budget (budget) <-> (stellenzuweisung) Stellenzuweisung [*]; + <> + association [0..1] Budget -> Organigramm [0..1]; + + //---------------------------------------------- + + // ------ Buchungseinträge ------ + // Konto -> 1Budget (->*Budget)* -> *Buchung + + /** + * Buchungen aller Arten: gemeinsame Oberklasse + */ + abstract class Buchungseintrag { + ZonedDateTime datum; + Optional buchungseintragText; // human name: Buchung: "Buchungstext", Rechnung: "Rechnungsgrund", Mittelabruf: "Anmerkung", Mittelzuweisung: "Grund" + long betragCent; // human name: "Betrag", Rechnung: "Rechnungsbetrag", Konten mit Programmpauschale: "Rechnungsbetrag (inkl Pauschale)" + boolean istAktiv; + Optional aenderungsdatum; + /Geschaeftsvorgang gueltigerGeschaeftsvorgang; + /String lfdeNummer; + } + + class Buchung extends Buchungseintrag { + ZonedDateTime belegdatum; + String zahlungsgrund; //Belegpositionstext + Optional kreditorDebitor; + List sachkonto; + Optional buchungsdatum; + BuchungsStatus status; + List belegnummern; + List auftragsnummer; + Optional bereich; + Optional projekt; + Optional geschaeftsjahr; + Optional steuer; + Optional skonto; + Optional gez_Skonto; + Optional erfasser; + Optional belegart; + Optional referenz; + Optional stornonummer; + Optional stkz; + Optional erfassungsdatum; + Optional ausgleichsdatum; + long betragCentOriginal; // Bei Abweichungen von BetragCent kann nun eine Absicht ueberprueft werden + boolean budgetChangedManually; // s.o. + Optional kostenarten; + /Optional bezugsdatumJahr; + } + + class Rechnungsstellung extends Buchungseintrag { + Optional rechnungsdatum; + Optional rechnungsnummer; + RechnungsstellungStatus status; + List belegnummern; + Optional gemeinkosten; + Optional honorierung; + Optional projekt; + Optional debitor; + Optional mehrwertsteuer; + Optional zahlungsziel; + } + + class Mittelzuweisung extends Buchungseintrag { + Optional verfallDatum; + Optional kennung; + MittelzuweisungStatus status; + } + + class Mittelabruf extends Buchungseintrag { + ZonedDateTime abrufdatum; + MittelabrufStatus status; + String zeitraum; + Optional pauschaleManuell; // Präsent, falls die Pauschale manuell geändert wurde + } + + // ------ Stellenzuweisung ------ + + // Konto -> 1Budget (->*Budget)* -> *Stellenzuweisung + + class Stellenzuweisung { + ZonedDateTime erstellDatum; // aktuelles Datum + Optional startDatum; // Datum, zu welchem die Stelle beginnt + Optional endDatum; // Datum, zu welchem die Stelle endet + long wert; + String kennung; + StellenzuweisungStatus status; + ZahlenWert stellenumfang; + boolean istAktiv; + Optional aenderungsdatum; + } + + enum Geschaeftsvorgang { + NONE, + MITTELABRUF, + ZUWEISUNG, + RECHNUNG; + } + + enum BuchungsStatus { + EINGEREICHT, + SAP("SAP"), + SAP_STORNIERT("SAP(Storniert)"), + PLANUNG, + FEHLERHAFT; + } + + enum RechnungsstellungStatus { + OFFENE_RECHNUNG, + SAP("SAP"), + SAP_STORNIERT("SAP(Storniert)"), + PLANUNG; + } + + enum MittelzuweisungStatus { + BESCHEID_ERHALTEN ("Bescheid erhalten"), + SAP("SAP"), + SAP_STORNIERT("SAP(Storniert)"), + PLANUNG, + FEHLERHAFT; + } + + enum MittelabrufStatus { + ABGERUFEN, + SAP("SAP"), + SAP_STORNIERT("SAP(Storniert)"), + PLANUNG, + EINGEREICHT; + } + + enum StellenzuweisungStatus { + BESETZT, + TEILBESETZT, + UNBESETZT, + PLANUNG; + } + + enum VertragStatus { + AKTIV, + PLANUNG, + ABGELAUFEN; + } + + //---------------------------------------------- + // =============== SAPii =============== + //---------------------------------------------- + + class SAPVerbindung { + SAPverbindungsStatus status; + } + + class Anfrage { + String ikz; + String bezeichner; + boolean letzteAnfrageErfolgreich; + } + + enum SAPverbindungsStatus { + VERBUNDEN, + GETRENNT, + PROBLEM; + } + + enum SAPimportMode { + DEFAULT, + F1KONTO; + } + + association [1] SAPVerbindung -> (authorizedBy) MacocoUser [*]; + association [1] MacocoUser -> (anfragen) Anfrage [*]; + association [1] Anfrage -> (filteredKonten) PSPImportFilter [*]; + + //---------------------------------------------- + + class AbgleichsBuchung extends Buchung { + AbgleichsStatus abgleichsStatus; + Optional abgleichKommentar; + String positionsNummer; + boolean deactivated; + } + + enum AbgleichsStatus { + ABGESCHLOSSEN, // Der Abgleich dieser Buchung ist Abgeschlossen + TEILWEISE_ABGESCHLOSSEN, // Der Abgleich wurde schon Bearbeitet es fehlen jedoch Summen + ABWEICHEND, // Der Abgleich ist Vollständig mit Abweichenden Summen + OFFEN, // Der Abgleich wurde noch nicht gesetzt + VORGESCHLAGEN; // Der Abgleich wurde vom System vorgeschlagen + } + + class AbgleichsGruppe { + String bezeichnung; + } + <> + association AbgleichsGruppe -> (buchungen) Buchung [*]; + <> + association AbgleichsGruppe -> (abgleichsBuchungen) AbgleichsBuchung [*]; + <> + association AbgleichsGruppe -> (konto) Konto [1]; + + // ------ Freitext ------ + + class Freitext { + Optional erstellDatum; + Optional bearbeitetDatum; + <> + Optional text; + } + + class Legende { + LegendeTyp type; + String expression; + <> + String description; + } + + enum LegendeTyp { + KONTO_FARBE; + } + + //---------------------------------------------- + // =============== Projekte =============== + //---------------------------------------------- + + abstract class Projekt { + String name; + String kuerzel; + Optional minPM; + Optional maxPM; + Optional finanzPM; + Optional laufzeitVon; + Optional laufzeitBis; + Optional kommentar; + Optional foerdergeberAZ; + ProjektStatus status; + boolean istAktiv; + boolean lockedForStundenzettel; // Das gesamte Projekt ist gesperrt + List lockedMonths; // Stellen die Ausnahme aus der Lock-Regelung für das gesamte Projekt dar + Optional aenderungsdatum; + } + + association [1] Projekt -> Aufwand [*]; + association [1] Projekt -> Arbeitspaket [*]; + association [1] Projekt -> Anstellung [*]; + association [*] Projekt -> Konto [0..1]; + association [*] Projekt -> (hauptverantwortlich) Person [*]; + association [1] Projekt -> (notiz) Freitext [0..1]; + + class Auftragsprojekt extends Projekt { + Optional nummer; + ProjektTyp typ; + Optional regelung; + } + + class Organisation extends Projekt { + } + + class Lehre extends Projekt { + Optional stunden; + } + + class Arbeitspaket { + String nummer; // könnte auch 1.1 sein + String name; + Optional beschreibung; + Optional beginnDatum; + Optional endeDatum; + Optional pMs; + Optional stunden; + Optional aenderungsdatum; + } + + class Aufwand { + /long pM; + ZahlenWert umfang; + ZonedDateTime laufzeitVon; + ZonedDateTime laufzeitBis; + Optional aenderungsdatum; + } + + association [*] Aufwand -> Person [0..1]; + + class Anstellung { + Optional bezeichnung; + ZahlenWert umfang; + ZonedDateTime von; + ZonedDateTime bis; + boolean verfaellt; + Optional min; + Optional max; + /long pM; + BeschaeftigungsArt beschaeftigungsArt; + } + + association [*] Anstellung -> Person [0..1]; + + class Stellentyp { + Optional entgeltgruppe; + Optional entgeltstufe; + } + + enum ProjektStatus { + IN_DEFINITION, + BEANTRAGT, + GENEHMIGT, + ABGELEHNT, + LAUFEND, + FACHLICH_ABGESCHLOSSEN("Fachlich abgeschlossen"), + ENDBERICHT_EINGEREICHT("Endbericht eingereicht"), + INPRUEFUNG("In Prüfung"), + GEPRUEFT("Geprüft"), + ABGERECHNET, + ABGESCHLOSSEN, + ARCHIVIERT; + } + + enum ProjektArt { + AUFTRAG, + ORGANISATION, + LEHRE, + NONE; + } + + enum ProjektTyp { + HOHEITLICH, + INDUSTRIE, + UNIVERSITAET("Universität"), + SONSTIGE; + } + + enum Vergabeverordnung { + VOL_A ("VOL/A"), + VOB_A ("VOB/A"), + UVGO_NRW ("UVgO NRW"), + UVGO_BUND ("UVgO Bund"), + NONE (" "); + } + + //---------------------------------------------- + // =============== Stundenzettel =============== + //---------------------------------------------- + + class Stundenzettel { + StundenzettelStatus status; + ZonedDateTime zeit; + Optional abgegebenVonUserId; + Optional abgabeDatum; + } + + association [1] Stundenzettel -> (eintraege) StundenzettelEintrag [*]; + + class StundenzettelEintrag { + ZonedDateTime uhrzeitVon; + Optional uhrzeitBis; + Optional beschreibung; + /long stunden; + StundenzettelProjekt pauseOderSonstiges; + } + + association [*] StundenzettelEintrag -> Projekt [0..1]; + association [*] StundenzettelEintrag -> Arbeitspaket [0..1]; + + class StundenzettelHistorieEintrag { + ZonedDateTime bearbeitungsdatum; + Optional editorId; + Optional editedBy; + String monat; + int jahr; + String changeOperation; + } + + enum StundenzettelChangeOperation { + INVALID, + ABGEGEBEN("Abgegeben"), + INTERN_GEPRUEFT("Intern Geprüft"), + INTERN_ABGESCHLOSSEN("Intern Abgeschlossen"); + } + + association [1] Person -> StundenzettelHistorieEintrag [*]; + + class Abwesenheit { + Abwesenheitsgrund grund; + ZonedDateTime datumVon; + ZonedDateTime datumBis; + Optional kommentar; + Optional uhrzeitVon; + Optional uhrzeitBis; + Optional minutenProTag; + /long tageGesamt; + } + + class Dienstreise extends Abwesenheit { + Optional reisenummer; + Optional dienstreisegrund; + Optional reiseziel; + Optional gesamtkosten; + Optional status; + Optional statusText; + } + + association [*] Abwesenheit -> Konto [0..1]; + + association [1] Abwesenheit -> UrlaubsGenehmigung [0..1]; + + association [*] Dienstreise -> Budget [0..1]; + + class Arbeitstage { + ZonedDateTime guiltigAb; + ZonedDateTime guiltigBis; + List wochenTage; // 0..4 (Montag-Freitag) + } + + association [1] Person -> Arbeitstage [*]; + + class Jahresurlaub { + int jahr; + long tageAnzahl; + Optional stundenAnzahl; + boolean istManuellerEintrag; + } + + class UrlaubsGenehmigung { + Optional beantragt; + Optional genehmigt; + Optional geprueft; + Optional storniert; + Urlaubssstatus status; + Stornierungsstatus stornierungsStatus; + } + + class Sonderurlaub { // Für WZL: Zusatzurlaub umbenennen in Sonderurlaub und neues Feld anzahl + ZonedDateTime datumVon; + ZonedDateTime datumBis; + long anzahl; + } + + class UrlaubEinstellungen { + boolean urlaubsanspruchInStunden; + } + + enum Abwesenheitsgrund { + U_URLAUB, + D_DIENSTREISE, + S_SONSTIGE; + /* + Z_ZUSATZURLAUB, + A_ARBEITSUNFALL, + AB_ABGELTUNG, + E_ELTERNZEIT, + F_FREISTELLUNG, + K_KRANKHEIT, + KU_KUR, + S_SONSTIGES;*/ + } + + enum Urlaubssstatus { + NONE, + BEANTRAGT, + GEPRUEFT("Geprüft"), + PRUEFUNG_ABGELEHNT("Prüfung abgelehnt"), + GENEHMIGT, + GENEHMIGUNG_ABGELEHNT; + } + + enum Stornierungsstatus { + NONE, + VERBOTEN, + STORNIERUNGSANTRAG, + STORNIERT; + } + + enum Abrechnungsstatus { + OFFEN, + ABZURECHNEN, + ABGERECHNET, + STORNIERT; + } + + enum StundenzettelStatus { + IN_ERFASSUNG, + INTERN_INPRUEFUNG("Intern in Prüfung"), + INTERN_ABGESCHLOSSEN, + DRITTMITTELABTEILUNG_INPRUEFUNG("Drittmittelabteilung in Prüfung"), + DRITTMITTELABTEILUNG_ABGESCHLOSSEN, + ENDBERICHT_EINGEREICHT, + GEPRUEFT("Geprüft"), + FOERDERGEBER_ABGESCHLOSSEN("Fördergeber abgeschlossen"), + ABGESCHLOSSEN; + } + + enum StundenzettelProjekt { + PAUSE, + SONSTIGE, + NONE; + } + + association [*] F1Konto -> (institut) Institut [0..1]; + + class ExternKonto extends Konto { + Optional startDatum; + Optional endDatum; + Optional importVermerk; + AbgleichType abgleichVerhalten; + } + + enum AbgleichType { + IGNORE, + MANUEL, + AUTO_COPY; + } + + association [*] ExternKonto -> (institut) Institut [0..1]; + + class PSPImportFilter{ + boolean importThisPSPelement; + boolean importBookings; + String name; + String pspElement; + Optional startDate; + } + + association [*] PSPImportFilter -> (targetPSP) Konto [0..1]; + + //---------------------------------------------- + // Reports + + class EventReport { + ZonedDateTime eventStart; + Optional eventEnd; + /EventStatus status; + String message; // BuchungImport: Nutzer 'netz' hat die Datei '.....' importiert + } + + class EventReportEntry { + EventType type; + Optional targetId; // click -> navigate to id + Optional count; + <> + String message; // Zeile 4 Fehler ...... Zeile 5 ..... + EventStatus status; + } + association [1] EventReport -> (entries) EventReportEntry [*]; + + class ImportReport extends EventReport { + } + + class ImportReportEntry extends EventReportEntry { + } + + + class PersonalExportReport extends EventReport { + Long dataId; + + ZonedDateTime datenStart; + ZonedDateTime datenEnd; + Long countData; + /Long countError; + EventStatus exportStatus; + } + + class PersonalExportReportEntry extends EventReportEntry { + Optional vorsatzwort; + String vorname; + String nachname; + BeschaeftigungsArt beschaeftigungsArt; + ZonedDateTime monat; + } + + enum EventStatus { + // Import + SUCCESS("erfolgreich"), + ERROR("fehlerhaft"), + INFO("erfolgreich"), // success + special + CREATED("erstellt"), + UPDATED("upgedated"), + IGNORED("ignoriert"), + IN_PROGRESS("in bearbeitung"), + + // Personal Export + SENT("verschickt"), + CORRECT("sachlich korrekt"); + } + + enum EventType { + IMPORT_KONTO("Konten"), + IMPORT_BUCHUNG("Buchungs"), + IMPORT_PERSON("Personen"), + IMPORT_INSTITUT("Instituts"), + IMPORT_NUTZER("Nutzer"), + IMPORT_VERTRAG("Vertrags"), + EXPORT_FINANZEN_KONTO("Konten"), + EXPORT_FINANZEN_PLANSTELLE("Planstellen"), + EXPORT_FINANZEN_VERTRAG("Vertragabdeckungs"); + } + + + //---------------------------------------------- + // =============== Fakultät 1 DS =============== + //---------------------------------------------- + + // Institut + <> + class Institut { + String institutsKennZiffer; + String institutsName; + String professorName; + boolean lokalInstitut; + } + + // Fachgruppe + enum Fachgruppe { + MATHEMATIK, + INFORMATIK, + PHYSIK, + CHEMIE, + BIOLOGIE; + } + + //SAP-Abschöpfung von Geschäftsjahr + class GeschaeftsjahrSAPAbschoepfung { + String fachgruppe; + String institutsKennZiffer; + String institutsName; + String pspElement; + long gesamtSAPAbschoepfung; + } + + class SAPAbschoepfung { + Long betragCent; + ZonedDateTime year; + } + + association [1] GeschaeftsjahrSAPAbschoepfung -> (sapAbschoepfung) SAPAbschoepfung [*]; + + + // Konto + class F1Konto extends Haushaltskonto { + Optional startDatum; + Optional endDatum; + long originalBudgetCent; + long sonstigeZuweisungenCent; + long resteCent; + long aktuellerKontostandCent; + long kontoRahmenCent; + KommunikationsStatus kommunikationsStatus; + StrafsteuerStatus strafsteuerStatus; + long strafsteuerBasisCent; + long strafsteuerSAPCent; + long strafsteuerCent; + long strafsteuerBerechnungsGrundlageCent; + Optional kontoStandBeginnGeschaeftsjahr; + } + + // Konto -> 1Budget (->*Budget)* -> *Buchung -> ?Begruendung + + // Buchungen werden hier noch erweitert: + association [1] Buchung -> (begruendung) Begruendung [0..1]; + + class Begruendung { + String text; + ZonedDateTime erstellung; + Optional letzteBearbeitung; + Optional geschaeftsjahr; + } + + association [1] Begruendung -> (akzeptanz) Akzeptanz [0..1]; + //association [1] Begruendung -> (geschaeftsjahr) StrafsteuerGeschaeftsjahr [0..1]; + + //---------------------------------------------- + + // Konto -> 1Budget (->*Budget)* -> *Buchung -> ?Begruendung -> ?Akzeptanz + + class Akzeptanz { + Akzeptanzstatus akzeptanzstatus; + Optional teilbetragCent; + Optional bearbeitung; + boolean istAktiv; + Optional kommentar; + } + + //---------------------------------------------- + + enum KommunikationsStatus { + KOM_STAT_NO_ACTION_NEEDED, // Kein Handlungsbedarf + KOM_STAT_BEGR_FEHLT, // Begründung fehlt + KOM_STAT_ANTW_FEHLT, // Antwort fehlt + KOM_STAT_ANTW_CHANGED, // Buchung oder Begründung wurden geändert + KOM_STAT_BEGR_CHANGED, // Antwort wurde geändert + KOM_STAT_ANTW_BEGR_CHANGED, // Antwort und Begründung wurde geändert + KOM_STAT_ANTW_FEHLT_CHANGED; // Antwort Fehlt, andere Antwort wurde geändert + } + + enum StrafsteuerStatus { + NONE, + SOME, + ALL; + } + + enum Akzeptanzstatus { + OFFEN, + OK, + TEILOK, + NOTOK; + } + + class StrafsteuerGeschaeftsjahr { + ZonedDateTime jahr; + boolean current; + } + + class StrafsteuerSperrDatum { + ZonedDateTime sperrDatum; + } + + //---------------------------------------------- + // =============== MacocoUser =============== + //---------------------------------------------- + + class MacocoUser { + <> + String username; + Optional encodedPassword; + String passwordSaltBase64; + ZonedDateTime registrationDate; + Optional initials; + MacocoUserActivationStatus activated; + boolean enabled; + <> + String email; + boolean authentifiziert; + Optional timID; + Optional sapAccessToken; + Optional sapRefreshToKen; + + } + + association [*] MacocoUser -> (institute) Institut [*]; + + enum MacocoUserActivationStatus { + AKTIVIERT, + MAIL_NICHT_GESENDET("Mail nicht gesendet"), + MAIL_FEHLERHAFT("Mail fehlerhaft"), + MAIL_GESENDET("Mail gesendet"); + } + + // Favoriten + class Favorite { + String title; + String url; + } + + association [1] MacocoUser -> (favorite) Favorite [*]; + + class RoleAssignment { + } + + association [*] RoleAssignment -> (user) MacocoUser [1]; + association [*] RoleAssignment -> (accessPolicy) AccessPolicy [1]; + + class AccessPolicy { + String roleName; + Optional objId; + } + + class GroupedAccessPolicy { + String name; + } + + association [*] GroupedAccessPolicy -> (user) MacocoUser [*]; + association [1] GroupedAccessPolicy -> (policy) AccessPolicy [*]; + + //---------------------------------------------- + // =============== Fristen =============== + //---------------------------------------------- + + class Frist { + String beschreibung; + Friststatus status; + Fristobjekt fristobjekt; + ZonedDateTime faelligkeitsdatum; + Optional notiz; + Boolean manuellerEintrag; + Long bezugsobjektId; + String bezugsobjektName; + Optional aenderungsdatum; + boolean istAktiv; + } + + association [*] Frist -> (zuweisung) Person [0..1]; + + association [1] Person -> Frist [*]; + association [1] Konto -> Frist [*]; + association [1] Projekt -> Frist [*]; + association [1] Mittelabruf -> Frist [0..1]; + association [1] Rechnungsstellung -> Frist [0..1]; + association [1] Vertrag -> Frist [0..1]; + association [1] Zulage -> Frist [0..1]; + + enum Friststatus { + PLANUNG, + IN_BEARBEITUNG, + ERLEDIGT; + } + + enum Fristobjekt { + PERSON, + KONTO, + VERTRAGSVERLAENGERUNG("Vertragsverlängerung"), + ZULAGE, + RECHNUNG, + MITTELABRUF, + PROJEKT; + } + + class DefaultFristen { + ZonedDateTime finanzenStartDatum; + Long finanzenFristinWeeks; + ZonedDateTime personalStartDatum; + Long personalFristinWeeks; + } + + //---------------------------------------------- + // ============= Einstellungen ================= + //---------------------------------------------- + + class Setting { + String identifier; + } + + class InstanzSetting extends Setting { + String value; + } + + class UISetting extends Setting { + String seite; + } + + association [0..1] MacocoUser -> (setting) UISetting [*]; + + class FilterSetting extends UISetting { + List filterValues; + } + + class TableSetting extends UISetting { + TableIdentifierTyp typ; + boolean zeigeInaktive; + int zeilenLimit; + Optional gruppiereNach; + Optional sortiereNach; + Optional sortiereDir; + boolean isShowColor; + } + + association [1] TableSetting -> (spalten) TableSettingSpalten [*]; + + enum TableIdentifierTyp { + DEFAULT, + USER, + INSTITUT; + } + + class TableSettingSpalten { + String name; + boolean istAktiv; + long breite; + } + + class ErweiterbareListen{ + String bereich; + String feldbezeichnung; + List inhalte; + } + + //---------------------------------------------- + // =============== Card Settings =============== + //---------------------------------------------- + + class CardSetting { + String page; + String identifier; + <> + String configuration; + } + + association [*] CardSetting -> (benutzer) MacocoUser [0..1]; + + //---------------------------------------------- + // =============== WZL =============== + //---------------------------------------------- + + class Elternzeit { // WZL + Optional von; + Optional bis; + ZahlenWert umfang; + } + + class Nebentaetigkeit { // WZL + Optional von; + Optional bis; + ZahlenWert umfang; + Optional arbeitgeber; + Optional taetigkeitsbereich; + } + + class Zulage { // WZL + Optional pspelement; + Optional bezeichnung; + ZonedDateTime von; + ZonedDateTime bis; + Long arbeitgeberbrutto; + Long arbeitnehmerbrutto; + } + + // WZL + enum Geschlecht { NONE(""), WEIBLICH("weiblich"), MAENNLICH("männlich"), DIVERS("divers"); } + + // WZL + // -> DataSource + enum Titel { NONE(""), E1("Apl. Prof. Dr.") , E2("B.Sc.") , E3("Dipl.-Inform.") , E4("Dipl.-Ing."), E5("Dipl.-Ing. (FH)"), + E6("Dipl.-Ing. (RUS)"), E7("Dipl.-Kff.") , E8("Dipl.-Math."), E9("Dipl.-Phys.") , E10("Dipl.-Wirt. Ing.") , E11("Dr.") , E12("Dr. phil."), + E13("Dr. rer. nat."), E14("Dr. rer. pol."), E15("Dr.-Ing."), E16("M.A.") , E17("M.Eng."), E18("M.Sc."), E19("PhD"), E20("Prof. Dr.-Ing."); } + + // WZL + // -> DataSource + enum Berufsgruppe { NONE(""), E1("Akademischer Direktor"), E2("Angestellter in der DV"), E3("Auszubildende/r"), E4("Bibl.-Beschäftiger"), + E5("Elektriker"), E6("Elektroniker"), E7("Elektrotechniker"), E8("Fachinformatiker"), E9("Fachinformatiker"), E10("Industriemechaniker"), + E11("Lagerarbeiter"), E12("Mechaniker"), E13("Meister"), E14("Praktikant, SV-frei"), E15("Programmierer"), E16("Stud. Hilfskraft"), + E17("Techn. Beschäftigter"), E18("Techn. Zeichner"), E19("Techniker"), E20("Universitätsprofessor"), E21("Verw. Beschäftigter"), E22("Werkstoffprüfer"), + E23("Wiss. Beschäftigter"), E24("Wiss. Hilfskraft Bachelor"), E25("Wiss. Hilfskraft Master"); } + + // WZL + enum Aktion { NONE(""), ANFRAGE_VERSENDET("Anfrage versendet"), ERINNERUNG_VERSENDET("Erinnerung versendet"), + ZUR_UNTERSCHRIFT_BEIM_VORGESETZTEN("Zur Unterschrift beim Vorgesetzten"), + BEI_ZHV_VORGELEGT("Bei ZHV vorgelegt"), VON_ZHV_BESTAETIGT("Von ZHV bestätigt"); } + + // WZL + // -> DataSource + enum Vertragsgrundlage { NONE(""), E1("sonst. Befristungen (gleicht Auszubildenden)"), E2("unbefristet"), E3("unbefr. (Beamter aL)"), E4("§14 Abs. 2 TzBfG"), + E5("Elternzeitvertretung"), E6("Befristung SHK"), E7("Mehrbedarf sonstiger"), E8("Mehrb. Forschungspr."), E9("§2(5)Nr.3WZVG MuS-EZ"), + E10("§2 WZVG DM (NP)"), E11("§2 WZVG KiBetr NP"), E12("WZVG-Postdoc-Quali."), E13("WZVG-N-Gr._Leiter"), E14("WZVG-Wiss.-Quali NP"), + E15("§2 WZVG DM (VP)"), E16("§2 WZVG KiBetr VP"), E17("WZVG-Promotion"), E18("WZVG-sonst.Wiss-Qual"), E19("Befristung WHB"), E20("Befristung WHK"), + E21("§2 (1) S.2 WZVG nPr"), E22("§14(1) Nr.2 TzBfG-Üb"), E23("befr. Arbeitszeitänderung"), E24("Übernahme nach Ausbildung"); } + + association [1] Person -> (elternzeiten) Elternzeit [*]; // WZL + association [1] Person -> (nebentaetigkeiten) Nebentaetigkeit[*]; // WZL + association [1] Person -> (zulagen) Zulage [*]; // WZL + + // WZL Personal Export + class PersonalExportData { + } + association [1] PersonalExportData -> (entries) PersonalExportDataEntry [*]; + + class PersonalExportDataEntry { + String personalnummer; + Optional vorsatzwort; + String nachname; + String vorname; + ZonedDateTime von; + ZonedDateTime bis; + String pspElement; + Long prozentsatz; + } + + class PersonalExportEinstellungen { + String pspElement; + List bezeichnungen; + ZonedDateTime startmonat; + ZonedDateTime endmonat; + } + + class Organigramm { + boolean istStabstelle; + boolean istAktiv; + String bezeichnung; + } + + <> + association [0..1] Organigramm (parent) <-> (child) Organigramm [*]; + + association [1] Organigramm -> (leiter) OrganigrammPersonInfo [*]; + association [1] Organigramm -> (stellvertreter) OrganigrammPersonInfo [*]; + association [1] Organigramm -> (mitarbeiter) OrganigrammPersonInfo [*]; + + class OrganigrammPersonInfo { + Optional von; + Optional bis; + Optional umfang; + } + + association [*] OrganigrammPersonInfo -> Person [1]; + + //---------------------------------------------- + // =============== WZL END =============== + //---------------------------------------------- + + + // Druckeinstellungen + class DruckEinstellungenProjekt { + Long projektId; + Integer jahr; + Integer monat; + Optional mittelabrufnummer; + Optional belegnummer; + } + + association [1] DruckEinstellungenProjekt -> (druckEinstellungenPersonen) DruckEinstellungenPerson [*]; + + class DruckEinstellungenPerson { + Long personId; + Optional stundensatz; + } + + class BlacklistedToken { + <> // have more than 255 characters + String token; + ZonedDateTime addedAt; + ZonedDateTime expiresAt; + } + + class RefreshToken { + long userId; + String token; + } + + // NotificationCenter + class UserNotification { + UserNotificationType notificationType; + String title; + + <> + String message; + ZonedDateTime timeStamp; + + // clickable + Optional link; // fuer Router + + boolean seen; + boolean pinned; + } + + enum UserNotificationType { SUCCESS, INFO, WARNING, DANGER; } + + association [1] MacocoUser -> (notification) UserNotification [*]; + + //---------------------------------------------- + // =============== Command Logs ================ + //---------------------------------------------- + class AccessIdentifier { + } + + class CommandLog { + ZonedDateTime timestamp; + List diff; + String affectedArea; + String affectedObject; + } + + association [1] CommandLog -> (executor) MacocoUser [0..1]; // TODO: In den Migrationsskript für 2.9.0 -> 2.10.0 : früher war association [1] CommandLog -> (executor) MacocoUser [1]; + association [1] CommandLog -> (permission) AccessIdentifier [*]; + + //---------------------------------------------- + // =============== Dokumente =================== + //---------------------------------------------- + + // Bei Änderung PermissionCheckHelper.doesUserHavePermissionForDokument updaten + enum DokumentGroup { + PERSONAL("personal"), + KONTO("konto"); + } + + class Dokument { + DokumentGroup groupName; + Long associationId; // ID des Objektes an dem das Dokument hängt + ZonedDateTime datum; // Upload-Datum + String bezeichnung; + String dateiFormat; + Long fileSize; + Optional anmerkung; + boolean istAktiv; + } + +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichType.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichType.java new file mode 100644 index 00000000..7d4d28ec --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichType.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum AbgleichType { + IGNORE, + MANUEL, + AUTO_COPY; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichsBuchung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichsBuchung.java new file mode 100644 index 00000000..4d0310c9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichsBuchung.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"AbgleichsBuchung"}, template = "${}") +public class AbgleichsBuchung extends Buchung { + @Adapt(ref = {"AbgleichsBuchung.abgleichsStatus"}, template = "${}") + private AbgleichsStatus abgleichsStatus; + + @Adapt(ref = {"AbgleichsBuchung.abgleichKommentar"}, template = "${}") + private Optional abgleichKommentar; + + @Adapt(ref = {"AbgleichsBuchung.positionsNummer"}, template = "${}") + private String positionsNummer; + + @Adapt(ref = {"AbgleichsBuchung.deactivated"}, template = "${}") + private boolean deactivated; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichsGruppe.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichsGruppe.java new file mode 100644 index 00000000..f48d5ed5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichsGruppe.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"AbgleichsGruppe"}, template = "${}") +public class AbgleichsGruppe { + @Adapt(ref = {"AbgleichsGruppe.bezeichnung"}, template = "${}") + private String bezeichnung; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichsStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichsStatus.java new file mode 100644 index 00000000..e35d006a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbgleichsStatus.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum AbgleichsStatus { + ABGESCHLOSSEN, + TEILWEISE_ABGESCHLOSSEN, + ABWEICHEND, + OFFEN, + VORGESCHLAGEN; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbrechnungsInterval.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbrechnungsInterval.java new file mode 100644 index 00000000..e62d5d91 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AbrechnungsInterval.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum AbrechnungsInterval { + GESAMTE_PROJEKTLAUFZEIT, + JAEHRLICH, + HALBJAEHRLICH, + QUARTALSWEISE, + MONATLICH; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Abrechnungsstatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Abrechnungsstatus.java new file mode 100644 index 00000000..f747976e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Abrechnungsstatus.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Abrechnungsstatus { + OFFEN, + ABZURECHNEN, + ABGERECHNET, + STORNIERT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Abwesenheit.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Abwesenheit.java new file mode 100644 index 00000000..73aa2ba6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Abwesenheit.java @@ -0,0 +1,31 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Abwesenheit"}, template = "${}") +public class Abwesenheit { + @Adapt(ref = {"Abwesenheit.grund"}, template = "${}") + private Abwesenheitsgrund grund; + + @Adapt(ref = {"Abwesenheit.datumVon"}, template = "${}") + private ZonedDateTime datumVon; + + @Adapt(ref = {"Abwesenheit.datumBis"}, template = "${}") + private ZonedDateTime datumBis; + + @Adapt(ref = {"Abwesenheit.kommentar"}, template = "${}") + private Optional kommentar; + + @Adapt(ref = {"Abwesenheit.uhrzeitVon"}, template = "${}") + private Optional uhrzeitVon; + + @Adapt(ref = {"Abwesenheit.uhrzeitBis"}, template = "${}") + private Optional uhrzeitBis; + + @Adapt(ref = {"Abwesenheit.minutenProTag"}, template = "${}") + private Optional minutenProTag; + + @Adapt(ref = {"Abwesenheit.tageGesamt"}, template = "${}") + private long tageGesamt; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Abwesenheitsgrund.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Abwesenheitsgrund.java new file mode 100644 index 00000000..de5e5612 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Abwesenheitsgrund.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Abwesenheitsgrund { + U_URLAUB, + D_DIENSTREISE, + S_SONSTIGE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AccessIdentifier.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AccessIdentifier.java new file mode 100644 index 00000000..c5aa459c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AccessIdentifier.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"AccessIdentifier"}, template = "${}") +public class AccessIdentifier { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AccessPolicy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AccessPolicy.java new file mode 100644 index 00000000..904815ef --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/AccessPolicy.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"AccessPolicy"}, template = "${}") +public class AccessPolicy { + @Adapt(ref = {"AccessPolicy.roleName"}, template = "${}") + private String roleName; + + @Adapt(ref = {"AccessPolicy.objId"}, template = "${}") + private Optional objId; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Aktion.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Aktion.java new file mode 100644 index 00000000..05001219 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Aktion.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Aktion { + NONE, + ANFRAGE_VERSENDET, + ERINNERUNG_VERSENDET, + ZUR_UNTERSCHRIFT_BEIM_VORGESETZTEN, + BEI_ZHV_VORGELEGT, + VON_ZHV_BESTAETIGT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Akzeptanz.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Akzeptanz.java new file mode 100644 index 00000000..c4bdb0c5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Akzeptanz.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Akzeptanz"}, template = "${}") +public class Akzeptanz { + @Adapt(ref = {"Akzeptanz.akzeptanzstatus"}, template = "${}") + private Akzeptanzstatus akzeptanzstatus; + + @Adapt(ref = {"Akzeptanz.teilbetragCent"}, template = "${}") + private Optional teilbetragCent; + + @Adapt(ref = {"Akzeptanz.bearbeitung"}, template = "${}") + private Optional bearbeitung; + + @Adapt(ref = {"Akzeptanz.istAktiv"}, template = "${}") + private boolean istAktiv; + + @Adapt(ref = {"Akzeptanz.kommentar"}, template = "${}") + private Optional kommentar; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Akzeptanzstatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Akzeptanzstatus.java new file mode 100644 index 00000000..39ad726b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Akzeptanzstatus.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Akzeptanzstatus { + OFFEN, + OK, + TEILOK, + NOTOK; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anfrage.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anfrage.java new file mode 100644 index 00000000..0d358bbc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anfrage.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Anfrage"}, template = "${}") +public class Anfrage { + @Adapt(ref = {"Anfrage.ikz"}, template = "${}") + private String ikz; + + @Adapt(ref = {"Anfrage.bezeichner"}, template = "${}") + private String bezeichner; + + @Adapt(ref = {"Anfrage.letzteAnfrageErfolgreich"}, template = "${}") + private boolean letzteAnfrageErfolgreich; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anstellung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anstellung.java new file mode 100644 index 00000000..e002d2a0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anstellung.java @@ -0,0 +1,34 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Anstellung"}, template = "${}") +public class Anstellung { + @Adapt(ref = {"Anstellung.bezeichnung"}, template = "${}") + private Optional bezeichnung; + + @Adapt(ref = {"Anstellung.umfang"}, template = "${}") + private ZahlenWert umfang; + + @Adapt(ref = {"Anstellung.von"}, template = "${}") + private ZonedDateTime von; + + @Adapt(ref = {"Anstellung.bis"}, template = "${}") + private ZonedDateTime bis; + + @Adapt(ref = {"Anstellung.verfaellt"}, template = "${}") + private boolean verfaellt; + + @Adapt(ref = {"Anstellung.min"}, template = "${}") + private Optional min; + + @Adapt(ref = {"Anstellung.max"}, template = "${}") + private Optional max; + + @Adapt(ref = {"Anstellung.pM"}, template = "${}") + private long pM; + + @Adapt(ref = {"Anstellung.beschaeftigungsArt"}, template = "${}") + private BeschaeftigungsArt beschaeftigungsArt; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anstellungsart.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anstellungsart.java new file mode 100644 index 00000000..222a1d90 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anstellungsart.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Anstellungsart"}, template = "${}") +public class Anstellungsart { + @Adapt(ref = {"Anstellungsart.beschArt"}, template = "${}") + private BeschaeftigungsArt beschArt; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anstellungsform.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anstellungsform.java new file mode 100644 index 00000000..258b01fd --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Anstellungsform.java @@ -0,0 +1,43 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Anstellungsform"}, template = "${}") +public class Anstellungsform { + @Adapt(ref = {"Anstellungsform.erstanstellung"}, template = "${}") + private boolean erstanstellung; + + @Adapt(ref = {"Anstellungsform.entgeltGruppe"}, template = "${}") + private Optional entgeltGruppe; + + @Adapt(ref = {"Anstellungsform.erfahrungsStufe"}, template = "${}") + private Optional erfahrungsStufe; + + @Adapt(ref = {"Anstellungsform.unbefristet"}, template = "${}") + private boolean unbefristet; + + @Adapt(ref = {"Anstellungsform.anstellungVon"}, template = "${}") + private ZonedDateTime anstellungVon; + + @Adapt(ref = {"Anstellungsform.anstellungBis"}, template = "${}") + private Optional anstellungBis; + + @Adapt(ref = {"Anstellungsform.gehaltCent"}, template = "${}") + private long gehaltCent; + + @Adapt(ref = {"Anstellungsform.istEigenerReferenzwert"}, template = "${}") + private boolean istEigenerReferenzwert; + + @Adapt(ref = {"Anstellungsform.kommentar"}, template = "${}") + private List kommentar; + + @Adapt(ref = {"Anstellungsform.berufsgruppe"}, template = "${}") + private Optional berufsgruppe; + + @Adapt(ref = {"Anstellungsform.aktion"}, template = "${}") + private Optional aktion; + + @Adapt(ref = {"Anstellungsform.aktionsDatum"}, template = "${}") + private Optional aktionsDatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Arbeitspaket.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Arbeitspaket.java new file mode 100644 index 00000000..4b173e47 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Arbeitspaket.java @@ -0,0 +1,31 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Arbeitspaket"}, template = "${}") +public class Arbeitspaket { + @Adapt(ref = {"Arbeitspaket.nummer"}, template = "${}") + private String nummer; + + @Adapt(ref = {"Arbeitspaket.name"}, template = "${}") + private String name; + + @Adapt(ref = {"Arbeitspaket.beschreibung"}, template = "${}") + private Optional beschreibung; + + @Adapt(ref = {"Arbeitspaket.beginnDatum"}, template = "${}") + private Optional beginnDatum; + + @Adapt(ref = {"Arbeitspaket.endeDatum"}, template = "${}") + private Optional endeDatum; + + @Adapt(ref = {"Arbeitspaket.pMs"}, template = "${}") + private Optional pMs; + + @Adapt(ref = {"Arbeitspaket.stunden"}, template = "${}") + private Optional stunden; + + @Adapt(ref = {"Arbeitspaket.aenderungsdatum"}, template = "${}") + private Optional aenderungsdatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Arbeitstage.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Arbeitstage.java new file mode 100644 index 00000000..2e5b37ec --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Arbeitstage.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Arbeitstage"}, template = "${}") +public class Arbeitstage { + @Adapt(ref = {"Arbeitstage.guiltigAb"}, template = "${}") + private ZonedDateTime guiltigAb; + + @Adapt(ref = {"Arbeitstage.guiltigBis"}, template = "${}") + private ZonedDateTime guiltigBis; + + @Adapt(ref = {"Arbeitstage.wochenTage"}, template = "${}") + private List wochenTage; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Auftragsprojekt.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Auftragsprojekt.java new file mode 100644 index 00000000..8b1e1687 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Auftragsprojekt.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Auftragsprojekt"}, template = "${}") +public class Auftragsprojekt extends Projekt { + @Adapt(ref = {"Auftragsprojekt.nummer"}, template = "${}") + private Optional nummer; + + @Adapt(ref = {"Auftragsprojekt.typ"}, template = "${}") + private ProjektTyp typ; + + @Adapt(ref = {"Auftragsprojekt.regelung"}, template = "${}") + private Optional regelung; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Aufwand.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Aufwand.java new file mode 100644 index 00000000..a831ad52 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Aufwand.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Aufwand"}, template = "${}") +public class Aufwand { + @Adapt(ref = {"Aufwand.pM"}, template = "${}") + private long pM; + + @Adapt(ref = {"Aufwand.umfang"}, template = "${}") + private ZahlenWert umfang; + + @Adapt(ref = {"Aufwand.laufzeitVon"}, template = "${}") + private ZonedDateTime laufzeitVon; + + @Adapt(ref = {"Aufwand.laufzeitBis"}, template = "${}") + private ZonedDateTime laufzeitBis; + + @Adapt(ref = {"Aufwand.aenderungsdatum"}, template = "${}") + private Optional aenderungsdatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Begruendung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Begruendung.java new file mode 100644 index 00000000..af718165 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Begruendung.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Begruendung"}, template = "${}") +public class Begruendung { + @Adapt(ref = {"Begruendung.text"}, template = "${}") + private String text; + + @Adapt(ref = {"Begruendung.erstellung"}, template = "${}") + private ZonedDateTime erstellung; + + @Adapt(ref = {"Begruendung.letzteBearbeitung"}, template = "${}") + private Optional letzteBearbeitung; + + @Adapt(ref = {"Begruendung.geschaeftsjahr"}, template = "${}") + private Optional geschaeftsjahr; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Berufsgruppe.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Berufsgruppe.java new file mode 100644 index 00000000..bd90b979 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Berufsgruppe.java @@ -0,0 +1,30 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Berufsgruppe { + NONE, + E1, + E2, + E3, + E4, + E5, + E6, + E7, + E8, + E9, + E10, + E11, + E12, + E13, + E14, + E15, + E16, + E17, + E18, + E19, + E20, + E21, + E22, + E23, + E24, + E25; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/BeschaeftigungsArt.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/BeschaeftigungsArt.java new file mode 100644 index 00000000..f48d222d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/BeschaeftigungsArt.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum BeschaeftigungsArt { + WiMi, + HiWi, + BTV, + BEAMTE, + AZUBI, + PLAN; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/BlacklistedToken.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/BlacklistedToken.java new file mode 100644 index 00000000..2322d91d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/BlacklistedToken.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"BlacklistedToken"}, template = "${}") +public class BlacklistedToken { + @Adapt(ref = {"BlacklistedToken.token"}, template = "${}") + private String token; + + @Adapt(ref = {"BlacklistedToken.addedAt"}, template = "${}") + private ZonedDateTime addedAt; + + @Adapt(ref = {"BlacklistedToken.expiresAt"}, template = "${}") + private ZonedDateTime expiresAt; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Buchung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Buchung.java new file mode 100644 index 00000000..9a4b53bd --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Buchung.java @@ -0,0 +1,82 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Buchung"}, template = "${}") +public class Buchung extends Buchungseintrag { + @Adapt(ref = {"Buchung.belegdatum"}, template = "${}") + private ZonedDateTime belegdatum; + + @Adapt(ref = {"Buchung.zahlungsgrund"}, template = "${}") + private String zahlungsgrund; + + @Adapt(ref = {"Buchung.kreditorDebitor"}, template = "${}") + private Optional kreditorDebitor; + + @Adapt(ref = {"Buchung.sachkonto"}, template = "${}") + private List sachkonto; + + @Adapt(ref = {"Buchung.buchungsdatum"}, template = "${}") + private Optional buchungsdatum; + + @Adapt(ref = {"Buchung.status"}, template = "${}") + private BuchungsStatus status; + + @Adapt(ref = {"Buchung.belegnummern"}, template = "${}") + private List belegnummern; + + @Adapt(ref = {"Buchung.auftragsnummer"}, template = "${}") + private List auftragsnummer; + + @Adapt(ref = {"Buchung.bereich"}, template = "${}") + private Optional bereich; + + @Adapt(ref = {"Buchung.projekt"}, template = "${}") + private Optional projekt; + + @Adapt(ref = {"Buchung.geschaeftsjahr"}, template = "${}") + private Optional geschaeftsjahr; + + @Adapt(ref = {"Buchung.steuer"}, template = "${}") + private Optional steuer; + + @Adapt(ref = {"Buchung.skonto"}, template = "${}") + private Optional skonto; + + @Adapt(ref = {"Buchung.gez_Skonto"}, template = "${}") + private Optional gez_Skonto; + + @Adapt(ref = {"Buchung.erfasser"}, template = "${}") + private Optional erfasser; + + @Adapt(ref = {"Buchung.belegart"}, template = "${}") + private Optional belegart; + + @Adapt(ref = {"Buchung.referenz"}, template = "${}") + private Optional referenz; + + @Adapt(ref = {"Buchung.stornonummer"}, template = "${}") + private Optional stornonummer; + + @Adapt(ref = {"Buchung.stkz"}, template = "${}") + private Optional stkz; + + @Adapt(ref = {"Buchung.erfassungsdatum"}, template = "${}") + private Optional erfassungsdatum; + + @Adapt(ref = {"Buchung.ausgleichsdatum"}, template = "${}") + private Optional ausgleichsdatum; + + @Adapt(ref = {"Buchung.betragCentOriginal"}, template = "${}") + private long betragCentOriginal; + + @Adapt(ref = {"Buchung.budgetChangedManually"}, template = "${}") + private boolean budgetChangedManually; + + @Adapt(ref = {"Buchung.kostenarten"}, template = "${}") + private Optional kostenarten; + + @Adapt(ref = {"Buchung.bezugsdatumJahr"}, template = "${}") + private Optional bezugsdatumJahr; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/BuchungsStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/BuchungsStatus.java new file mode 100644 index 00000000..36651a4c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/BuchungsStatus.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum BuchungsStatus { + EINGEREICHT, + SAP, + SAP_STORNIERT, + PLANUNG, + FEHLERHAFT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Buchungseintrag.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Buchungseintrag.java new file mode 100644 index 00000000..2bcc40c6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Buchungseintrag.java @@ -0,0 +1,28 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Buchungseintrag"}, template = "${}") +public class Buchungseintrag { + @Adapt(ref = {"Buchungseintrag.datum"}, template = "${}") + private ZonedDateTime datum; + + @Adapt(ref = {"Buchungseintrag.buchungseintragText"}, template = "${}") + private Optional buchungseintragText; + + @Adapt(ref = {"Buchungseintrag.betragCent"}, template = "${}") + private long betragCent; + + @Adapt(ref = {"Buchungseintrag.istAktiv"}, template = "${}") + private boolean istAktiv; + + @Adapt(ref = {"Buchungseintrag.aenderungsdatum"}, template = "${}") + private Optional aenderungsdatum; + + @Adapt(ref = {"Buchungseintrag.gueltigerGeschaeftsvorgang"}, template = "${}") + private Geschaeftsvorgang gueltigerGeschaeftsvorgang; + + @Adapt(ref = {"Buchungseintrag.lfdeNummer"}, template = "${}") + private String lfdeNummer; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Budget.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Budget.java new file mode 100644 index 00000000..5bfa9c60 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Budget.java @@ -0,0 +1,40 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Budget"}, template = "${}") +public class Budget { + @Adapt(ref = {"Budget.typ"}, template = "${}") + private String typ; + + @Adapt(ref = {"Budget.startDatum"}, template = "${}") + private Optional startDatum; + + @Adapt(ref = {"Budget.endDatum"}, template = "${}") + private Optional endDatum; + + @Adapt(ref = {"Budget.kommentar"}, template = "${}") + private Optional kommentar; + + @Adapt(ref = {"Budget.budgetRahmenCent"}, template = "${}") + private Optional budgetRahmenCent; + + @Adapt(ref = {"Budget.eigenAnteilCent"}, template = "${}") + private Optional eigenAnteilCent; + + @Adapt(ref = {"Budget.jahresBudgets"}, template = "${}") + private List jahresBudgets; + + @Adapt(ref = {"Budget.proportionaleVerteilung"}, template = "${}") + private boolean proportionaleVerteilung; + + @Adapt(ref = {"Budget.forOverheads"}, template = "${}") + private boolean forOverheads; + + @Adapt(ref = {"Budget.budgetKategorie"}, template = "${}") + private Optional budgetKategorie; + + @Adapt(ref = {"Budget.budgetDepth"}, template = "${}") + private int budgetDepth; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/CardSetting.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/CardSetting.java new file mode 100644 index 00000000..ef495975 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/CardSetting.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"CardSetting"}, template = "${}") +public class CardSetting { + @Adapt(ref = {"CardSetting.page"}, template = "${}") + private String page; + + @Adapt(ref = {"CardSetting.identifier"}, template = "${}") + private String identifier; + + @Adapt(ref = {"CardSetting.configuration"}, template = "${}") + private String configuration; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/CommandLog.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/CommandLog.java new file mode 100644 index 00000000..0683ded8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/CommandLog.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"CommandLog"}, template = "${}") +public class CommandLog { + @Adapt(ref = {"CommandLog.timestamp"}, template = "${}") + private ZonedDateTime timestamp; + + @Adapt(ref = {"CommandLog.diff"}, template = "${}") + private List diff; + + @Adapt(ref = {"CommandLog.affectedArea"}, template = "${}") + private String affectedArea; + + @Adapt(ref = {"CommandLog.affectedObject"}, template = "${}") + private String affectedObject; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DefaultFristen.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DefaultFristen.java new file mode 100644 index 00000000..f9bd97b5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DefaultFristen.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DefaultFristen"}, template = "${}") +public class DefaultFristen { + @Adapt(ref = {"DefaultFristen.finanzenStartDatum"}, template = "${}") + private ZonedDateTime finanzenStartDatum; + + @Adapt(ref = {"DefaultFristen.finanzenFristinWeeks"}, template = "${}") + private Long finanzenFristinWeeks; + + @Adapt(ref = {"DefaultFristen.personalStartDatum"}, template = "${}") + private ZonedDateTime personalStartDatum; + + @Adapt(ref = {"DefaultFristen.personalFristinWeeks"}, template = "${}") + private Long personalFristinWeeks; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Dienstreise.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Dienstreise.java new file mode 100644 index 00000000..c781a874 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Dienstreise.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Dienstreise"}, template = "${}") +public class Dienstreise extends Abwesenheit { + @Adapt(ref = {"Dienstreise.reisenummer"}, template = "${}") + private Optional reisenummer; + + @Adapt(ref = {"Dienstreise.dienstreisegrund"}, template = "${}") + private Optional dienstreisegrund; + + @Adapt(ref = {"Dienstreise.reiseziel"}, template = "${}") + private Optional reiseziel; + + @Adapt(ref = {"Dienstreise.gesamtkosten"}, template = "${}") + private Optional gesamtkosten; + + @Adapt(ref = {"Dienstreise.status"}, template = "${}") + private Optional status; + + @Adapt(ref = {"Dienstreise.statusText"}, template = "${}") + private Optional statusText; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Dokument.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Dokument.java new file mode 100644 index 00000000..f8c0aeba --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Dokument.java @@ -0,0 +1,31 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Dokument"}, template = "${}") +public class Dokument { + @Adapt(ref = {"Dokument.groupName"}, template = "${}") + private DokumentGroup groupName; + + @Adapt(ref = {"Dokument.associationId"}, template = "${}") + private Long associationId; + + @Adapt(ref = {"Dokument.datum"}, template = "${}") + private ZonedDateTime datum; + + @Adapt(ref = {"Dokument.bezeichnung"}, template = "${}") + private String bezeichnung; + + @Adapt(ref = {"Dokument.dateiFormat"}, template = "${}") + private String dateiFormat; + + @Adapt(ref = {"Dokument.fileSize"}, template = "${}") + private Long fileSize; + + @Adapt(ref = {"Dokument.anmerkung"}, template = "${}") + private Optional anmerkung; + + @Adapt(ref = {"Dokument.istAktiv"}, template = "${}") + private boolean istAktiv; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DokumentGroup.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DokumentGroup.java new file mode 100644 index 00000000..7c3ccf34 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DokumentGroup.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum DokumentGroup { + PERSONAL, + KONTO; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Drittmittelprojekt.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Drittmittelprojekt.java new file mode 100644 index 00000000..ff3e5b84 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Drittmittelprojekt.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Drittmittelprojekt"}, template = "${}") +public class Drittmittelprojekt extends ErweitertesKonto { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DruckEinstellungenPerson.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DruckEinstellungenPerson.java new file mode 100644 index 00000000..6cddbab3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DruckEinstellungenPerson.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DruckEinstellungenPerson"}, template = "${}") +public class DruckEinstellungenPerson { + @Adapt(ref = {"DruckEinstellungenPerson.personId"}, template = "${}") + private Long personId; + + @Adapt(ref = {"DruckEinstellungenPerson.stundensatz"}, template = "${}") + private Optional stundensatz; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DruckEinstellungenProjekt.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DruckEinstellungenProjekt.java new file mode 100644 index 00000000..827ed751 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/DruckEinstellungenProjekt.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DruckEinstellungenProjekt"}, template = "${}") +public class DruckEinstellungenProjekt { + @Adapt(ref = {"DruckEinstellungenProjekt.projektId"}, template = "${}") + private Long projektId; + + @Adapt(ref = {"DruckEinstellungenProjekt.jahr"}, template = "${}") + private Integer jahr; + + @Adapt(ref = {"DruckEinstellungenProjekt.monat"}, template = "${}") + private Integer monat; + + @Adapt(ref = {"DruckEinstellungenProjekt.mittelabrufnummer"}, template = "${}") + private Optional mittelabrufnummer; + + @Adapt(ref = {"DruckEinstellungenProjekt.belegnummer"}, template = "${}") + private Optional belegnummer; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Elternzeit.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Elternzeit.java new file mode 100644 index 00000000..13b62c02 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Elternzeit.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Elternzeit"}, template = "${}") +public class Elternzeit { + @Adapt(ref = {"Elternzeit.von"}, template = "${}") + private Optional von; + + @Adapt(ref = {"Elternzeit.bis"}, template = "${}") + private Optional bis; + + @Adapt(ref = {"Elternzeit.umfang"}, template = "${}") + private ZahlenWert umfang; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ErweiterbareListen.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ErweiterbareListen.java new file mode 100644 index 00000000..48c0e0be --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ErweiterbareListen.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"ErweiterbareListen"}, template = "${}") +public class ErweiterbareListen { + @Adapt(ref = {"ErweiterbareListen.bereich"}, template = "${}") + private String bereich; + + @Adapt(ref = {"ErweiterbareListen.feldbezeichnung"}, template = "${}") + private String feldbezeichnung; + + @Adapt(ref = {"ErweiterbareListen.inhalte"}, template = "${}") + private List inhalte; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ErweitertesKonto.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ErweitertesKonto.java new file mode 100644 index 00000000..a3e161da --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ErweitertesKonto.java @@ -0,0 +1,37 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"ErweitertesKonto"}, template = "${}") +public class ErweitertesKonto extends Konto { + @Adapt(ref = {"ErweitertesKonto.startDatum"}, template = "${}") + private Optional startDatum; + + @Adapt(ref = {"ErweitertesKonto.endDatum"}, template = "${}") + private Optional endDatum; + + @Adapt(ref = {"ErweitertesKonto.bewilligungsDatum"}, template = "${}") + private Optional bewilligungsDatum; + + @Adapt(ref = {"ErweitertesKonto.verlaengertBisDatum"}, template = "${}") + private Optional verlaengertBisDatum; + + @Adapt(ref = {"ErweitertesKonto.aufstockungsDatum"}, template = "${}") + private Optional aufstockungsDatum; + + @Adapt(ref = {"ErweitertesKonto.foerderquote"}, template = "${}") + private Optional foerderquote; + + @Adapt(ref = {"ErweitertesKonto.aktenzeichen"}, template = "${}") + private Optional aktenzeichen; + + @Adapt(ref = {"ErweitertesKonto.finanzierteKomplettsumme"}, template = "${}") + private Optional finanzierteKomplettsumme; + + @Adapt(ref = {"ErweitertesKonto.referenzSponsor"}, template = "${}") + private Optional referenzSponsor; + + @Adapt(ref = {"ErweitertesKonto.hatProgrammpauschale"}, template = "${}") + private boolean hatProgrammpauschale; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventReport.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventReport.java new file mode 100644 index 00000000..3618aa05 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventReport.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"EventReport"}, template = "${}") +public class EventReport { + @Adapt(ref = {"EventReport.eventStart"}, template = "${}") + private ZonedDateTime eventStart; + + @Adapt(ref = {"EventReport.eventEnd"}, template = "${}") + private Optional eventEnd; + + @Adapt(ref = {"EventReport.status"}, template = "${}") + private EventStatus status; + + @Adapt(ref = {"EventReport.message"}, template = "${}") + private String message; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventReportEntry.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventReportEntry.java new file mode 100644 index 00000000..993c7f1a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventReportEntry.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"EventReportEntry"}, template = "${}") +public class EventReportEntry { + @Adapt(ref = {"EventReportEntry.type"}, template = "${}") + private EventType type; + + @Adapt(ref = {"EventReportEntry.targetId"}, template = "${}") + private Optional targetId; + + @Adapt(ref = {"EventReportEntry.count"}, template = "${}") + private Optional count; + + @Adapt(ref = {"EventReportEntry.message"}, template = "${}") + private String message; + + @Adapt(ref = {"EventReportEntry.status"}, template = "${}") + private EventStatus status; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventStatus.java new file mode 100644 index 00000000..045c42dc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventStatus.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum EventStatus { + SUCCESS, + ERROR, + INFO, + CREATED, + UPDATED, + IGNORED, + IN_PROGRESS, + SENT, + CORRECT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventType.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventType.java new file mode 100644 index 00000000..b29836f7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/EventType.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum EventType { + IMPORT_KONTO, + IMPORT_BUCHUNG, + IMPORT_PERSON, + IMPORT_INSTITUT, + IMPORT_NUTZER, + IMPORT_VERTRAG, + EXPORT_FINANZEN_KONTO, + EXPORT_FINANZEN_PLANSTELLE, + EXPORT_FINANZEN_VERTRAG; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ExternKonto.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ExternKonto.java new file mode 100644 index 00000000..d050a5d6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ExternKonto.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"ExternKonto"}, template = "${}") +public class ExternKonto extends Konto { + @Adapt(ref = {"ExternKonto.startDatum"}, template = "${}") + private Optional startDatum; + + @Adapt(ref = {"ExternKonto.endDatum"}, template = "${}") + private Optional endDatum; + + @Adapt(ref = {"ExternKonto.importVermerk"}, template = "${}") + private Optional importVermerk; + + @Adapt(ref = {"ExternKonto.abgleichVerhalten"}, template = "${}") + private AbgleichType abgleichVerhalten; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/F1Konto.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/F1Konto.java new file mode 100644 index 00000000..3c42d6f6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/F1Konto.java @@ -0,0 +1,49 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"F1Konto"}, template = "${}") +public class F1Konto extends Haushaltskonto { + @Adapt(ref = {"F1Konto.startDatum"}, template = "${}") + private Optional startDatum; + + @Adapt(ref = {"F1Konto.endDatum"}, template = "${}") + private Optional endDatum; + + @Adapt(ref = {"F1Konto.originalBudgetCent"}, template = "${}") + private long originalBudgetCent; + + @Adapt(ref = {"F1Konto.sonstigeZuweisungenCent"}, template = "${}") + private long sonstigeZuweisungenCent; + + @Adapt(ref = {"F1Konto.resteCent"}, template = "${}") + private long resteCent; + + @Adapt(ref = {"F1Konto.aktuellerKontostandCent"}, template = "${}") + private long aktuellerKontostandCent; + + @Adapt(ref = {"F1Konto.kontoRahmenCent"}, template = "${}") + private long kontoRahmenCent; + + @Adapt(ref = {"F1Konto.kommunikationsStatus"}, template = "${}") + private KommunikationsStatus kommunikationsStatus; + + @Adapt(ref = {"F1Konto.strafsteuerStatus"}, template = "${}") + private StrafsteuerStatus strafsteuerStatus; + + @Adapt(ref = {"F1Konto.strafsteuerBasisCent"}, template = "${}") + private long strafsteuerBasisCent; + + @Adapt(ref = {"F1Konto.strafsteuerSAPCent"}, template = "${}") + private long strafsteuerSAPCent; + + @Adapt(ref = {"F1Konto.strafsteuerCent"}, template = "${}") + private long strafsteuerCent; + + @Adapt(ref = {"F1Konto.strafsteuerBerechnungsGrundlageCent"}, template = "${}") + private long strafsteuerBerechnungsGrundlageCent; + + @Adapt(ref = {"F1Konto.kontoStandBeginnGeschaeftsjahr"}, template = "${}") + private Optional kontoStandBeginnGeschaeftsjahr; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Fachgruppe.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Fachgruppe.java new file mode 100644 index 00000000..b8c3867c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Fachgruppe.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Fachgruppe { + MATHEMATIK, + INFORMATIK, + PHYSIK, + CHEMIE, + BIOLOGIE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Favorite.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Favorite.java new file mode 100644 index 00000000..a03b36a4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Favorite.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Favorite"}, template = "${}") +public class Favorite { + @Adapt(ref = {"Favorite.title"}, template = "${}") + private String title; + + @Adapt(ref = {"Favorite.url"}, template = "${}") + private String url; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/FilterSetting.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/FilterSetting.java new file mode 100644 index 00000000..13a8a6e4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/FilterSetting.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"FilterSetting"}, template = "${}") +public class FilterSetting extends UISetting { + @Adapt(ref = {"FilterSetting.filterValues"}, template = "${}") + private List filterValues; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Freitext.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Freitext.java new file mode 100644 index 00000000..9526b9c2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Freitext.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Freitext"}, template = "${}") +public class Freitext { + @Adapt(ref = {"Freitext.erstellDatum"}, template = "${}") + private Optional erstellDatum; + + @Adapt(ref = {"Freitext.bearbeitetDatum"}, template = "${}") + private Optional bearbeitetDatum; + + @Adapt(ref = {"Freitext.text"}, template = "${}") + private Optional text; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Frist.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Frist.java new file mode 100644 index 00000000..76c54d2b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Frist.java @@ -0,0 +1,37 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Frist"}, template = "${}") +public class Frist { + @Adapt(ref = {"Frist.beschreibung"}, template = "${}") + private String beschreibung; + + @Adapt(ref = {"Frist.status"}, template = "${}") + private Friststatus status; + + @Adapt(ref = {"Frist.fristobjekt"}, template = "${}") + private Fristobjekt fristobjekt; + + @Adapt(ref = {"Frist.faelligkeitsdatum"}, template = "${}") + private ZonedDateTime faelligkeitsdatum; + + @Adapt(ref = {"Frist.notiz"}, template = "${}") + private Optional notiz; + + @Adapt(ref = {"Frist.manuellerEintrag"}, template = "${}") + private Boolean manuellerEintrag; + + @Adapt(ref = {"Frist.bezugsobjektId"}, template = "${}") + private Long bezugsobjektId; + + @Adapt(ref = {"Frist.bezugsobjektName"}, template = "${}") + private String bezugsobjektName; + + @Adapt(ref = {"Frist.aenderungsdatum"}, template = "${}") + private Optional aenderungsdatum; + + @Adapt(ref = {"Frist.istAktiv"}, template = "${}") + private boolean istAktiv; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Fristobjekt.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Fristobjekt.java new file mode 100644 index 00000000..0bdc48d7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Fristobjekt.java @@ -0,0 +1,11 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Fristobjekt { + PERSON, + KONTO, + VERTRAGSVERLAENGERUNG, + ZULAGE, + RECHNUNG, + MITTELABRUF, + PROJEKT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Friststatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Friststatus.java new file mode 100644 index 00000000..b1cfbb67 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Friststatus.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Friststatus { + PLANUNG, + IN_BEARBEITUNG, + ERLEDIGT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/GeschaeftsjahrSAPAbschoepfung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/GeschaeftsjahrSAPAbschoepfung.java new file mode 100644 index 00000000..a6df3791 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/GeschaeftsjahrSAPAbschoepfung.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"GeschaeftsjahrSAPAbschoepfung"}, template = "${}") +public class GeschaeftsjahrSAPAbschoepfung { + @Adapt(ref = {"GeschaeftsjahrSAPAbschoepfung.fachgruppe"}, template = "${}") + private String fachgruppe; + + @Adapt(ref = {"GeschaeftsjahrSAPAbschoepfung.institutsKennZiffer"}, template = "${}") + private String institutsKennZiffer; + + @Adapt(ref = {"GeschaeftsjahrSAPAbschoepfung.institutsName"}, template = "${}") + private String institutsName; + + @Adapt(ref = {"GeschaeftsjahrSAPAbschoepfung.pspElement"}, template = "${}") + private String pspElement; + + @Adapt(ref = {"GeschaeftsjahrSAPAbschoepfung.gesamtSAPAbschoepfung"}, template = "${}") + private long gesamtSAPAbschoepfung; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Geschaeftsvorgang.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Geschaeftsvorgang.java new file mode 100644 index 00000000..92876aee --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Geschaeftsvorgang.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Geschaeftsvorgang { + NONE, + MITTELABRUF, + ZUWEISUNG, + RECHNUNG; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Geschlecht.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Geschlecht.java new file mode 100644 index 00000000..1758c5f7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Geschlecht.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Geschlecht { + NONE, + WEIBLICH, + MAENNLICH, + DIVERS; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/GroupedAccessPolicy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/GroupedAccessPolicy.java new file mode 100644 index 00000000..fa887c2c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/GroupedAccessPolicy.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"GroupedAccessPolicy"}, template = "${}") +public class GroupedAccessPolicy { + @Adapt(ref = {"GroupedAccessPolicy.name"}, template = "${}") + private String name; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Haushaltskonto.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Haushaltskonto.java new file mode 100644 index 00000000..00b44f22 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Haushaltskonto.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Haushaltskonto"}, template = "${}") +public class Haushaltskonto extends Konto { + @Adapt(ref = {"Haushaltskonto.startDatum"}, template = "${}") + private Optional startDatum; + + @Adapt(ref = {"Haushaltskonto.endDatum"}, template = "${}") + private Optional endDatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ImportReport.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ImportReport.java new file mode 100644 index 00000000..f16b705a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ImportReport.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"ImportReport"}, template = "${}") +public class ImportReport extends EventReport { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ImportReportEntry.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ImportReportEntry.java new file mode 100644 index 00000000..f7ad81c8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ImportReportEntry.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"ImportReportEntry"}, template = "${}") +public class ImportReportEntry extends EventReportEntry { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Industrieprojekt.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Industrieprojekt.java new file mode 100644 index 00000000..98df2b99 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Industrieprojekt.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Industrieprojekt"}, template = "${}") +public class Industrieprojekt extends ErweitertesKonto { + @Adapt(ref = {"Industrieprojekt.auftraggeber"}, template = "${}") + private Optional auftraggeber; + + @Adapt(ref = {"Industrieprojekt.istSammelkonto"}, template = "${}") + private boolean istSammelkonto; + + @Adapt(ref = {"Industrieprojekt.mehrwertsteuer"}, template = "${}") + private Optional mehrwertsteuer; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/InstanzSetting.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/InstanzSetting.java new file mode 100644 index 00000000..c70815de --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/InstanzSetting.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"InstanzSetting"}, template = "${}") +public class InstanzSetting extends Setting { + @Adapt(ref = {"InstanzSetting.value"}, template = "${}") + private String value; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Institut.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Institut.java new file mode 100644 index 00000000..c0fc5281 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Institut.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Institut"}, template = "${}") +public class Institut { + @Adapt(ref = {"Institut.institutsKennZiffer"}, template = "${}") + private String institutsKennZiffer; + + @Adapt(ref = {"Institut.institutsName"}, template = "${}") + private String institutsName; + + @Adapt(ref = {"Institut.professorName"}, template = "${}") + private String professorName; + + @Adapt(ref = {"Institut.lokalInstitut"}, template = "${}") + private boolean lokalInstitut; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Jahresurlaub.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Jahresurlaub.java new file mode 100644 index 00000000..676077e6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Jahresurlaub.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Jahresurlaub"}, template = "${}") +public class Jahresurlaub { + @Adapt(ref = {"Jahresurlaub.jahr"}, template = "${}") + private int jahr; + + @Adapt(ref = {"Jahresurlaub.tageAnzahl"}, template = "${}") + private long tageAnzahl; + + @Adapt(ref = {"Jahresurlaub.stundenAnzahl"}, template = "${}") + private Optional stundenAnzahl; + + @Adapt(ref = {"Jahresurlaub.istManuellerEintrag"}, template = "${}") + private boolean istManuellerEintrag; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/KommunikationsStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/KommunikationsStatus.java new file mode 100644 index 00000000..1592bef2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/KommunikationsStatus.java @@ -0,0 +1,11 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum KommunikationsStatus { + KOM_STAT_NO_ACTION_NEEDED, + KOM_STAT_BEGR_FEHLT, + KOM_STAT_ANTW_FEHLT, + KOM_STAT_ANTW_CHANGED, + KOM_STAT_BEGR_CHANGED, + KOM_STAT_ANTW_BEGR_CHANGED, + KOM_STAT_ANTW_FEHLT_CHANGED; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Konto.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Konto.java new file mode 100644 index 00000000..7745ddce --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Konto.java @@ -0,0 +1,49 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Konto"}, template = "${}") +public class Konto { + @Adapt(ref = {"Konto.name"}, template = "${}") + private String name; + + @Adapt(ref = {"Konto.pspElement"}, template = "${}") + private Optional pspElement; + + @Adapt(ref = {"Konto.kontotyp"}, template = "${}") + private Optional kontotyp; + + @Adapt(ref = {"Konto.sapDatum"}, template = "${}") + private Optional sapDatum; + + @Adapt(ref = {"Konto.internesAktenzeichen"}, template = "${}") + private Optional internesAktenzeichen; + + @Adapt(ref = {"Konto.istPlanKonto"}, template = "${}") + private boolean istPlanKonto; + + @Adapt(ref = {"Konto.istVerbuchungsKonto"}, template = "${}") + private boolean istVerbuchungsKonto; + + @Adapt(ref = {"Konto.istAktiv"}, template = "${}") + private boolean istAktiv; + + @Adapt(ref = {"Konto.vergabeVerordnung"}, template = "${}") + private Optional vergabeVerordnung; + + @Adapt(ref = {"Konto.farbe"}, template = "${}") + private Optional farbe; + + @Adapt(ref = {"Konto.aenderungsdatum"}, template = "${}") + private Optional aenderungsdatum; + + @Adapt(ref = {"Konto.optStartDatum"}, template = "${}") + private Optional optStartDatum; + + @Adapt(ref = {"Konto.optEndDatum"}, template = "${}") + private Optional optEndDatum; + + @Adapt(ref = {"Konto.gueltigerGeschaeftsvorgang"}, template = "${}") + private Geschaeftsvorgang gueltigerGeschaeftsvorgang; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Kostenstelle.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Kostenstelle.java new file mode 100644 index 00000000..8f269d0c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Kostenstelle.java @@ -0,0 +1,31 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Kostenstelle"}, template = "${}") +public class Kostenstelle { + @Adapt(ref = {"Kostenstelle.verbuchungsBeginn"}, template = "${}") + private ZonedDateTime verbuchungsBeginn; + + @Adapt(ref = {"Kostenstelle.verbuchungsEnde"}, template = "${}") + private ZonedDateTime verbuchungsEnde; + + @Adapt(ref = {"Kostenstelle.bezeichnung"}, template = "${}") + private KostenstelleBezeichnung bezeichnung; + + @Adapt(ref = {"Kostenstelle.kommentar"}, template = "${}") + private List kommentar; + + @Adapt(ref = {"Kostenstelle.beschaeftigungsUmfang"}, template = "${}") + private ZahlenWert beschaeftigungsUmfang; + + @Adapt(ref = {"Kostenstelle.buchungenNeuErzeugen"}, template = "${}") + private boolean buchungenNeuErzeugen; + + @Adapt(ref = {"Kostenstelle.buchungenLoeschen"}, template = "${}") + private boolean buchungenLoeschen; + + @Adapt(ref = {"Kostenstelle.gesperrt"}, template = "${}") + private boolean gesperrt; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/KostenstelleBezeichnung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/KostenstelleBezeichnung.java new file mode 100644 index 00000000..75daa7ba --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/KostenstelleBezeichnung.java @@ -0,0 +1,11 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum KostenstelleBezeichnung { + NONE, + AN_INSTITUT, + GMBH, + ANDERER_LEHRSTUHL, + ANDERES_INSTITUT, + VORUEBERGEHEND_ABWESEND, + ANDERE_FINANZIERUNG; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Legende.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Legende.java new file mode 100644 index 00000000..cc357b0b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Legende.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Legende"}, template = "${}") +public class Legende { + @Adapt(ref = {"Legende.type"}, template = "${}") + private LegendeTyp type; + + @Adapt(ref = {"Legende.expression"}, template = "${}") + private String expression; + + @Adapt(ref = {"Legende.description"}, template = "${}") + private String description; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/LegendeTyp.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/LegendeTyp.java new file mode 100644 index 00000000..de541e2e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/LegendeTyp.java @@ -0,0 +1,5 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum LegendeTyp { + KONTO_FARBE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Lehre.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Lehre.java new file mode 100644 index 00000000..8ebfd407 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Lehre.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Lehre"}, template = "${}") +public class Lehre extends Projekt { + @Adapt(ref = {"Lehre.stunden"}, template = "${}") + private Optional stunden; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MacocoUser.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MacocoUser.java new file mode 100644 index 00000000..7638e00a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MacocoUser.java @@ -0,0 +1,43 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"MacocoUser"}, template = "${}") +public class MacocoUser { + @Adapt(ref = {"MacocoUser.username"}, template = "${}") + private String username; + + @Adapt(ref = {"MacocoUser.encodedPassword"}, template = "${}") + private Optional encodedPassword; + + @Adapt(ref = {"MacocoUser.passwordSaltBase64"}, template = "${}") + private String passwordSaltBase64; + + @Adapt(ref = {"MacocoUser.registrationDate"}, template = "${}") + private ZonedDateTime registrationDate; + + @Adapt(ref = {"MacocoUser.initials"}, template = "${}") + private Optional initials; + + @Adapt(ref = {"MacocoUser.activated"}, template = "${}") + private MacocoUserActivationStatus activated; + + @Adapt(ref = {"MacocoUser.enabled"}, template = "${}") + private boolean enabled; + + @Adapt(ref = {"MacocoUser.email"}, template = "${}") + private String email; + + @Adapt(ref = {"MacocoUser.authentifiziert"}, template = "${}") + private boolean authentifiziert; + + @Adapt(ref = {"MacocoUser.timID"}, template = "${}") + private Optional timID; + + @Adapt(ref = {"MacocoUser.sapAccessToken"}, template = "${}") + private Optional sapAccessToken; + + @Adapt(ref = {"MacocoUser.sapRefreshToKen"}, template = "${}") + private Optional sapRefreshToKen; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MacocoUserActivationStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MacocoUserActivationStatus.java new file mode 100644 index 00000000..ffaaac92 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MacocoUserActivationStatus.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum MacocoUserActivationStatus { + AKTIVIERT, + MAIL_NICHT_GESENDET, + MAIL_FEHLERHAFT, + MAIL_GESENDET; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MailAlert.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MailAlert.java new file mode 100644 index 00000000..6f118b40 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MailAlert.java @@ -0,0 +1,52 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"MailAlert"}, template = "${}") +public class MailAlert { + @Adapt(ref = {"MailAlert.name"}, template = "${}") + private String name; + + @Adapt(ref = {"MailAlert.alertCondition"}, template = "${}") + private String alertCondition; + + @Adapt(ref = {"MailAlert.mailBody"}, template = "${}") + private String mailBody; + + @Adapt(ref = {"MailAlert.repetitions"}, template = "${}") + private int repetitions; + + @Adapt(ref = {"MailAlert.firstAlert"}, template = "${}") + private ZonedDateTime firstAlert; + + @Adapt(ref = {"MailAlert.lastAlert"}, template = "${}") + private ZonedDateTime lastAlert; + + @Adapt(ref = {"MailAlert.receipients"}, template = "${}") + private Optional receipients; + + @Adapt(ref = {"MailAlert.ccs"}, template = "${}") + private Optional ccs; + + @Adapt(ref = {"MailAlert.bccs"}, template = "${}") + private Optional bccs; + + @Adapt(ref = {"MailAlert.a1"}, template = "${}") + private long a1; + + @Adapt(ref = {"MailAlert.a2"}, template = "${}") + private long a2; + + @Adapt(ref = {"MailAlert.flag1"}, template = "${}") + private boolean flag1; + + @Adapt(ref = {"MailAlert.flag2"}, template = "${}") + private boolean flag2; + + @Adapt(ref = {"MailAlert.s1"}, template = "${}") + private String s1; + + @Adapt(ref = {"MailAlert.s2"}, template = "${}") + private String s2; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Mittelabruf.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Mittelabruf.java new file mode 100644 index 00000000..a12b1f1b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Mittelabruf.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Mittelabruf"}, template = "${}") +public class Mittelabruf extends Buchungseintrag { + @Adapt(ref = {"Mittelabruf.abrufdatum"}, template = "${}") + private ZonedDateTime abrufdatum; + + @Adapt(ref = {"Mittelabruf.status"}, template = "${}") + private MittelabrufStatus status; + + @Adapt(ref = {"Mittelabruf.zeitraum"}, template = "${}") + private String zeitraum; + + @Adapt(ref = {"Mittelabruf.pauschaleManuell"}, template = "${}") + private Optional pauschaleManuell; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MittelabrufStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MittelabrufStatus.java new file mode 100644 index 00000000..0af37dde --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MittelabrufStatus.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum MittelabrufStatus { + ABGERUFEN, + SAP, + SAP_STORNIERT, + PLANUNG, + EINGEREICHT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Mittelzuweisung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Mittelzuweisung.java new file mode 100644 index 00000000..a70c8267 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Mittelzuweisung.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Mittelzuweisung"}, template = "${}") +public class Mittelzuweisung extends Buchungseintrag { + @Adapt(ref = {"Mittelzuweisung.verfallDatum"}, template = "${}") + private Optional verfallDatum; + + @Adapt(ref = {"Mittelzuweisung.kennung"}, template = "${}") + private Optional kennung; + + @Adapt(ref = {"Mittelzuweisung.status"}, template = "${}") + private MittelzuweisungStatus status; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MittelzuweisungStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MittelzuweisungStatus.java new file mode 100644 index 00000000..53d7ad69 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/MittelzuweisungStatus.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum MittelzuweisungStatus { + BESCHEID_ERHALTEN, + SAP, + SAP_STORNIERT, + PLANUNG, + FEHLERHAFT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Nebentaetigkeit.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Nebentaetigkeit.java new file mode 100644 index 00000000..c2cd08b8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Nebentaetigkeit.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Nebentaetigkeit"}, template = "${}") +public class Nebentaetigkeit { + @Adapt(ref = {"Nebentaetigkeit.von"}, template = "${}") + private Optional von; + + @Adapt(ref = {"Nebentaetigkeit.bis"}, template = "${}") + private Optional bis; + + @Adapt(ref = {"Nebentaetigkeit.umfang"}, template = "${}") + private ZahlenWert umfang; + + @Adapt(ref = {"Nebentaetigkeit.arbeitgeber"}, template = "${}") + private Optional arbeitgeber; + + @Adapt(ref = {"Nebentaetigkeit.taetigkeitsbereich"}, template = "${}") + private Optional taetigkeitsbereich; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Organigramm.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Organigramm.java new file mode 100644 index 00000000..6eafb595 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Organigramm.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Organigramm"}, template = "${}") +public class Organigramm { + @Adapt(ref = {"Organigramm.istStabstelle"}, template = "${}") + private boolean istStabstelle; + + @Adapt(ref = {"Organigramm.istAktiv"}, template = "${}") + private boolean istAktiv; + + @Adapt(ref = {"Organigramm.bezeichnung"}, template = "${}") + private String bezeichnung; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/OrganigrammKonto.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/OrganigrammKonto.java new file mode 100644 index 00000000..d80aaea8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/OrganigrammKonto.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"OrganigrammKonto"}, template = "${}") +public class OrganigrammKonto { + @Adapt(ref = {"OrganigrammKonto.von"}, template = "${}") + private Optional von; + + @Adapt(ref = {"OrganigrammKonto.bis"}, template = "${}") + private Optional bis; + + @Adapt(ref = {"OrganigrammKonto.umfang"}, template = "${}") + private Optional umfang; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/OrganigrammPersonInfo.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/OrganigrammPersonInfo.java new file mode 100644 index 00000000..6aac8b45 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/OrganigrammPersonInfo.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"OrganigrammPersonInfo"}, template = "${}") +public class OrganigrammPersonInfo { + @Adapt(ref = {"OrganigrammPersonInfo.von"}, template = "${}") + private Optional von; + + @Adapt(ref = {"OrganigrammPersonInfo.bis"}, template = "${}") + private Optional bis; + + @Adapt(ref = {"OrganigrammPersonInfo.umfang"}, template = "${}") + private Optional umfang; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Organisation.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Organisation.java new file mode 100644 index 00000000..18bc55a3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Organisation.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Organisation"}, template = "${}") +public class Organisation extends Projekt { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PSPImportFilter.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PSPImportFilter.java new file mode 100644 index 00000000..9a31372d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PSPImportFilter.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"PSPImportFilter"}, template = "${}") +public class PSPImportFilter { + @Adapt(ref = {"PSPImportFilter.importThisPSPelement"}, template = "${}") + private boolean importThisPSPelement; + + @Adapt(ref = {"PSPImportFilter.importBookings"}, template = "${}") + private boolean importBookings; + + @Adapt(ref = {"PSPImportFilter.name"}, template = "${}") + private String name; + + @Adapt(ref = {"PSPImportFilter.pspElement"}, template = "${}") + private String pspElement; + + @Adapt(ref = {"PSPImportFilter.startDate"}, template = "${}") + private Optional startDate; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Person.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Person.java new file mode 100644 index 00000000..44e13235 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Person.java @@ -0,0 +1,103 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Person"}, template = "${}") +public class Person { + @Adapt(ref = {"Person.vorname"}, template = "${}") + private String vorname; + + @Adapt(ref = {"Person.vorsatzwort"}, template = "${}") + private Optional vorsatzwort; + + @Adapt(ref = {"Person.nachname"}, template = "${}") + private String nachname; + + @Adapt(ref = {"Person.kuerzel"}, template = "${}") + private String kuerzel; + + @Adapt(ref = {"Person.personalnummer"}, template = "${}") + private Optional personalnummer; + + @Adapt(ref = {"Person.gebDatum"}, template = "${}") + private Optional gebDatum; + + @Adapt(ref = {"Person.beschBeginn"}, template = "${}") + private Optional beschBeginn; + + @Adapt(ref = {"Person.beschEnde"}, template = "${}") + private Optional beschEnde; + + @Adapt(ref = {"Person.kommentar"}, template = "${}") + private List kommentar; + + @Adapt(ref = {"Person.istAktiv"}, template = "${}") + private boolean istAktiv; + + @Adapt(ref = {"Person.istStundenzettelpflichtig"}, template = "${}") + private boolean istStundenzettelpflichtig; + + @Adapt(ref = {"Person.stundenzettelpflichtigVon"}, template = "${}") + private Optional stundenzettelpflichtigVon; + + @Adapt(ref = {"Person.stundenzettelpflichtigBis"}, template = "${}") + private Optional stundenzettelpflichtigBis; + + @Adapt(ref = {"Person.ueberStundenUebertrag"}, template = "${}") + private Optional ueberStundenUebertrag; + + @Adapt(ref = {"Person.darfWochenendarbeiten"}, template = "${}") + private boolean darfWochenendarbeiten; + + @Adapt(ref = {"Person.hoechstbeschaeftigungBis"}, template = "${}") + private Optional hoechstbeschaeftigungBis; + + @Adapt(ref = {"Person.staatsangehoerigkeiten"}, template = "${}") + private List staatsangehoerigkeiten; + + @Adapt(ref = {"Person.telefonnummer"}, template = "${}") + private Optional telefonnummer; + + @Adapt(ref = {"Person.arbeitserlaubnisBis"}, template = "${}") + private Optional arbeitserlaubnisBis; + + @Adapt(ref = {"Person.extern"}, template = "${}") + private boolean extern; + + @Adapt(ref = {"Person.titel"}, template = "${}") + private Optional titel; + + @Adapt(ref = {"Person.rufname"}, template = "${}") + private Optional rufname; + + @Adapt(ref = {"Person.adresse"}, template = "${}") + private Optional adresse; + + @Adapt(ref = {"Person.email"}, template = "${}") + private Optional email; + + @Adapt(ref = {"Person.geburtsname"}, template = "${}") + private Optional geburtsname; + + @Adapt(ref = {"Person.geschlecht"}, template = "${}") + private Optional geschlecht; + + @Adapt(ref = {"Person.lBVNummer"}, template = "${}") + private Optional lBVNummer; + + @Adapt(ref = {"Person.entfristung"}, template = "${}") + private Optional entfristung; + + @Adapt(ref = {"Person.qualifikationstitel"}, template = "${}") + private Optional qualifikationstitel; + + @Adapt(ref = {"Person.speicherungGewuenscht"}, template = "${}") + private boolean speicherungGewuenscht; + + @Adapt(ref = {"Person.urlaubskommentar"}, template = "${}") + private Optional urlaubskommentar; + + @Adapt(ref = {"Person.aenderungsdatum"}, template = "${}") + private Optional aenderungsdatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportData.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportData.java new file mode 100644 index 00000000..0f50f598 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportData.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"PersonalExportData"}, template = "${}") +public class PersonalExportData { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportDataEntry.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportDataEntry.java new file mode 100644 index 00000000..e1242460 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportDataEntry.java @@ -0,0 +1,31 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"PersonalExportDataEntry"}, template = "${}") +public class PersonalExportDataEntry { + @Adapt(ref = {"PersonalExportDataEntry.personalnummer"}, template = "${}") + private String personalnummer; + + @Adapt(ref = {"PersonalExportDataEntry.vorsatzwort"}, template = "${}") + private Optional vorsatzwort; + + @Adapt(ref = {"PersonalExportDataEntry.nachname"}, template = "${}") + private String nachname; + + @Adapt(ref = {"PersonalExportDataEntry.vorname"}, template = "${}") + private String vorname; + + @Adapt(ref = {"PersonalExportDataEntry.von"}, template = "${}") + private ZonedDateTime von; + + @Adapt(ref = {"PersonalExportDataEntry.bis"}, template = "${}") + private ZonedDateTime bis; + + @Adapt(ref = {"PersonalExportDataEntry.pspElement"}, template = "${}") + private String pspElement; + + @Adapt(ref = {"PersonalExportDataEntry.prozentsatz"}, template = "${}") + private Long prozentsatz; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportEinstellungen.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportEinstellungen.java new file mode 100644 index 00000000..e0ef5c5b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportEinstellungen.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"PersonalExportEinstellungen"}, template = "${}") +public class PersonalExportEinstellungen { + @Adapt(ref = {"PersonalExportEinstellungen.pspElement"}, template = "${}") + private String pspElement; + + @Adapt(ref = {"PersonalExportEinstellungen.bezeichnungen"}, template = "${}") + private List bezeichnungen; + + @Adapt(ref = {"PersonalExportEinstellungen.startmonat"}, template = "${}") + private ZonedDateTime startmonat; + + @Adapt(ref = {"PersonalExportEinstellungen.endmonat"}, template = "${}") + private ZonedDateTime endmonat; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportReport.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportReport.java new file mode 100644 index 00000000..9e15c8e7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportReport.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"PersonalExportReport"}, template = "${}") +public class PersonalExportReport extends EventReport { + @Adapt(ref = {"PersonalExportReport.dataId"}, template = "${}") + private Long dataId; + + @Adapt(ref = {"PersonalExportReport.datenStart"}, template = "${}") + private ZonedDateTime datenStart; + + @Adapt(ref = {"PersonalExportReport.datenEnd"}, template = "${}") + private ZonedDateTime datenEnd; + + @Adapt(ref = {"PersonalExportReport.countData"}, template = "${}") + private Long countData; + + @Adapt(ref = {"PersonalExportReport.countError"}, template = "${}") + private Long countError; + + @Adapt(ref = {"PersonalExportReport.exportStatus"}, template = "${}") + private EventStatus exportStatus; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportReportEntry.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportReportEntry.java new file mode 100644 index 00000000..ee2a9df3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/PersonalExportReportEntry.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"PersonalExportReportEntry"}, template = "${}") +public class PersonalExportReportEntry extends EventReportEntry { + @Adapt(ref = {"PersonalExportReportEntry.vorsatzwort"}, template = "${}") + private Optional vorsatzwort; + + @Adapt(ref = {"PersonalExportReportEntry.vorname"}, template = "${}") + private String vorname; + + @Adapt(ref = {"PersonalExportReportEntry.nachname"}, template = "${}") + private String nachname; + + @Adapt(ref = {"PersonalExportReportEntry.beschaeftigungsArt"}, template = "${}") + private BeschaeftigungsArt beschaeftigungsArt; + + @Adapt(ref = {"PersonalExportReportEntry.monat"}, template = "${}") + private ZonedDateTime monat; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Planstelle.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Planstelle.java new file mode 100644 index 00000000..f8cabc69 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Planstelle.java @@ -0,0 +1,37 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Planstelle"}, template = "${}") +public class Planstelle { + @Adapt(ref = {"Planstelle.bezeichnung"}, template = "${}") + private String bezeichnung; + + @Adapt(ref = {"Planstelle.minEntgeltgruppe"}, template = "${}") + private Optional minEntgeltgruppe; + + @Adapt(ref = {"Planstelle.minEntgeltstufe"}, template = "${}") + private Optional minEntgeltstufe; + + @Adapt(ref = {"Planstelle.maxEntgeltgruppe"}, template = "${}") + private Optional maxEntgeltgruppe; + + @Adapt(ref = {"Planstelle.maxEntgeltstufe"}, template = "${}") + private Optional maxEntgeltstufe; + + @Adapt(ref = {"Planstelle.verfuegbarVon"}, template = "${}") + private Optional verfuegbarVon; + + @Adapt(ref = {"Planstelle.verfuegbarBis"}, template = "${}") + private Optional verfuegbarBis; + + @Adapt(ref = {"Planstelle.kommentar"}, template = "${}") + private Optional kommentar; + + @Adapt(ref = {"Planstelle.planUmfang"}, template = "${}") + private ZahlenWert planUmfang; + + @Adapt(ref = {"Planstelle.aktiv"}, template = "${}") + private boolean aktiv; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Projekt.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Projekt.java new file mode 100644 index 00000000..30a3b07d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Projekt.java @@ -0,0 +1,49 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Projekt"}, template = "${}") +public class Projekt { + @Adapt(ref = {"Projekt.name"}, template = "${}") + private String name; + + @Adapt(ref = {"Projekt.kuerzel"}, template = "${}") + private String kuerzel; + + @Adapt(ref = {"Projekt.minPM"}, template = "${}") + private Optional minPM; + + @Adapt(ref = {"Projekt.maxPM"}, template = "${}") + private Optional maxPM; + + @Adapt(ref = {"Projekt.finanzPM"}, template = "${}") + private Optional finanzPM; + + @Adapt(ref = {"Projekt.laufzeitVon"}, template = "${}") + private Optional laufzeitVon; + + @Adapt(ref = {"Projekt.laufzeitBis"}, template = "${}") + private Optional laufzeitBis; + + @Adapt(ref = {"Projekt.kommentar"}, template = "${}") + private Optional kommentar; + + @Adapt(ref = {"Projekt.foerdergeberAZ"}, template = "${}") + private Optional foerdergeberAZ; + + @Adapt(ref = {"Projekt.status"}, template = "${}") + private ProjektStatus status; + + @Adapt(ref = {"Projekt.istAktiv"}, template = "${}") + private boolean istAktiv; + + @Adapt(ref = {"Projekt.lockedForStundenzettel"}, template = "${}") + private boolean lockedForStundenzettel; + + @Adapt(ref = {"Projekt.lockedMonths"}, template = "${}") + private List lockedMonths; + + @Adapt(ref = {"Projekt.aenderungsdatum"}, template = "${}") + private Optional aenderungsdatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ProjektArt.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ProjektArt.java new file mode 100644 index 00000000..f0ba382e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ProjektArt.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum ProjektArt { + AUFTRAG, + ORGANISATION, + LEHRE, + NONE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ProjektStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ProjektStatus.java new file mode 100644 index 00000000..c29fcabf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ProjektStatus.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum ProjektStatus { + IN_DEFINITION, + BEANTRAGT, + GENEHMIGT, + ABGELEHNT, + LAUFEND, + FACHLICH_ABGESCHLOSSEN, + ENDBERICHT_EINGEREICHT, + INPRUEFUNG, + GEPRUEFT, + ABGERECHNET, + ABGESCHLOSSEN, + ARCHIVIERT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ProjektTyp.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ProjektTyp.java new file mode 100644 index 00000000..a7c370e6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ProjektTyp.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum ProjektTyp { + HOHEITLICH, + INDUSTRIE, + UNIVERSITAET, + SONSTIGE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Rechnungsstellung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Rechnungsstellung.java new file mode 100644 index 00000000..8669c2be --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Rechnungsstellung.java @@ -0,0 +1,37 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Rechnungsstellung"}, template = "${}") +public class Rechnungsstellung extends Buchungseintrag { + @Adapt(ref = {"Rechnungsstellung.rechnungsdatum"}, template = "${}") + private Optional rechnungsdatum; + + @Adapt(ref = {"Rechnungsstellung.rechnungsnummer"}, template = "${}") + private Optional rechnungsnummer; + + @Adapt(ref = {"Rechnungsstellung.status"}, template = "${}") + private RechnungsstellungStatus status; + + @Adapt(ref = {"Rechnungsstellung.belegnummern"}, template = "${}") + private List belegnummern; + + @Adapt(ref = {"Rechnungsstellung.gemeinkosten"}, template = "${}") + private Optional gemeinkosten; + + @Adapt(ref = {"Rechnungsstellung.honorierung"}, template = "${}") + private Optional honorierung; + + @Adapt(ref = {"Rechnungsstellung.projekt"}, template = "${}") + private Optional projekt; + + @Adapt(ref = {"Rechnungsstellung.debitor"}, template = "${}") + private Optional debitor; + + @Adapt(ref = {"Rechnungsstellung.mehrwertsteuer"}, template = "${}") + private Optional mehrwertsteuer; + + @Adapt(ref = {"Rechnungsstellung.zahlungsziel"}, template = "${}") + private Optional zahlungsziel; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/RechnungsstellungStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/RechnungsstellungStatus.java new file mode 100644 index 00000000..ae67b089 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/RechnungsstellungStatus.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum RechnungsstellungStatus { + OFFENE_RECHNUNG, + SAP, + SAP_STORNIERT, + PLANUNG; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/RefreshToken.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/RefreshToken.java new file mode 100644 index 00000000..09c4653e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/RefreshToken.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"RefreshToken"}, template = "${}") +public class RefreshToken { + @Adapt(ref = {"RefreshToken.userId"}, template = "${}") + private long userId; + + @Adapt(ref = {"RefreshToken.token"}, template = "${}") + private String token; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/RoleAssignment.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/RoleAssignment.java new file mode 100644 index 00000000..ff120f40 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/RoleAssignment.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"RoleAssignment"}, template = "${}") +public class RoleAssignment { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPAbschoepfung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPAbschoepfung.java new file mode 100644 index 00000000..2597b648 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPAbschoepfung.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"SAPAbschoepfung"}, template = "${}") +public class SAPAbschoepfung { + @Adapt(ref = {"SAPAbschoepfung.betragCent"}, template = "${}") + private Long betragCent; + + @Adapt(ref = {"SAPAbschoepfung.year"}, template = "${}") + private ZonedDateTime year; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPVerbindung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPVerbindung.java new file mode 100644 index 00000000..9c5c9fd0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPVerbindung.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"SAPVerbindung"}, template = "${}") +public class SAPVerbindung { + @Adapt(ref = {"SAPVerbindung.status"}, template = "${}") + private SAPverbindungsStatus status; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPimportMode.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPimportMode.java new file mode 100644 index 00000000..fdb0eeda --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPimportMode.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum SAPimportMode { + DEFAULT, + F1KONTO; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPverbindungsStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPverbindungsStatus.java new file mode 100644 index 00000000..2f387d95 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/SAPverbindungsStatus.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum SAPverbindungsStatus { + VERBUNDEN, + GETRENNT, + PROBLEM; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Setting.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Setting.java new file mode 100644 index 00000000..0fd5fdbe --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Setting.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Setting"}, template = "${}") +public class Setting { + @Adapt(ref = {"Setting.identifier"}, template = "${}") + private String identifier; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Sonderurlaub.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Sonderurlaub.java new file mode 100644 index 00000000..76a92995 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Sonderurlaub.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Sonderurlaub"}, template = "${}") +public class Sonderurlaub { + @Adapt(ref = {"Sonderurlaub.datumVon"}, template = "${}") + private ZonedDateTime datumVon; + + @Adapt(ref = {"Sonderurlaub.datumBis"}, template = "${}") + private ZonedDateTime datumBis; + + @Adapt(ref = {"Sonderurlaub.anzahl"}, template = "${}") + private long anzahl; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Sonstiges.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Sonstiges.java new file mode 100644 index 00000000..ae6c9765 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Sonstiges.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Sonstiges"}, template = "${}") +public class Sonstiges extends ErweitertesKonto { + @Adapt(ref = {"Sonstiges.auftraggeber"}, template = "${}") + private Optional auftraggeber; + + @Adapt(ref = {"Sonstiges.geschaeftsvorgang"}, template = "${}") + private Geschaeftsvorgang geschaeftsvorgang; + + @Adapt(ref = {"Sonstiges.mehrwertsteuer"}, template = "${}") + private Optional mehrwertsteuer; + + @Adapt(ref = {"Sonstiges.istSammelkonto"}, template = "${}") + private boolean istSammelkonto; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stellentyp.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stellentyp.java new file mode 100644 index 00000000..f4e04bcf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stellentyp.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Stellentyp"}, template = "${}") +public class Stellentyp { + @Adapt(ref = {"Stellentyp.entgeltgruppe"}, template = "${}") + private Optional entgeltgruppe; + + @Adapt(ref = {"Stellentyp.entgeltstufe"}, template = "${}") + private Optional entgeltstufe; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stellenzuweisung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stellenzuweisung.java new file mode 100644 index 00000000..d5aa688d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stellenzuweisung.java @@ -0,0 +1,34 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Stellenzuweisung"}, template = "${}") +public class Stellenzuweisung { + @Adapt(ref = {"Stellenzuweisung.erstellDatum"}, template = "${}") + private ZonedDateTime erstellDatum; + + @Adapt(ref = {"Stellenzuweisung.startDatum"}, template = "${}") + private Optional startDatum; + + @Adapt(ref = {"Stellenzuweisung.endDatum"}, template = "${}") + private Optional endDatum; + + @Adapt(ref = {"Stellenzuweisung.wert"}, template = "${}") + private long wert; + + @Adapt(ref = {"Stellenzuweisung.kennung"}, template = "${}") + private String kennung; + + @Adapt(ref = {"Stellenzuweisung.status"}, template = "${}") + private StellenzuweisungStatus status; + + @Adapt(ref = {"Stellenzuweisung.stellenumfang"}, template = "${}") + private ZahlenWert stellenumfang; + + @Adapt(ref = {"Stellenzuweisung.istAktiv"}, template = "${}") + private boolean istAktiv; + + @Adapt(ref = {"Stellenzuweisung.aenderungsdatum"}, template = "${}") + private Optional aenderungsdatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StellenzuweisungStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StellenzuweisungStatus.java new file mode 100644 index 00000000..c0bba7a8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StellenzuweisungStatus.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum StellenzuweisungStatus { + BESETZT, + TEILBESETZT, + UNBESETZT, + PLANUNG; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stornierungsstatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stornierungsstatus.java new file mode 100644 index 00000000..c25934b0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stornierungsstatus.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Stornierungsstatus { + NONE, + VERBOTEN, + STORNIERUNGSANTRAG, + STORNIERT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StrafsteuerGeschaeftsjahr.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StrafsteuerGeschaeftsjahr.java new file mode 100644 index 00000000..5f7ca617 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StrafsteuerGeschaeftsjahr.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"StrafsteuerGeschaeftsjahr"}, template = "${}") +public class StrafsteuerGeschaeftsjahr { + @Adapt(ref = {"StrafsteuerGeschaeftsjahr.jahr"}, template = "${}") + private ZonedDateTime jahr; + + @Adapt(ref = {"StrafsteuerGeschaeftsjahr.current"}, template = "${}") + private boolean current; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StrafsteuerSperrDatum.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StrafsteuerSperrDatum.java new file mode 100644 index 00000000..cdd21595 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StrafsteuerSperrDatum.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"StrafsteuerSperrDatum"}, template = "${}") +public class StrafsteuerSperrDatum { + @Adapt(ref = {"StrafsteuerSperrDatum.sperrDatum"}, template = "${}") + private ZonedDateTime sperrDatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StrafsteuerStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StrafsteuerStatus.java new file mode 100644 index 00000000..ad11ddba --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StrafsteuerStatus.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum StrafsteuerStatus { + NONE, + SOME, + ALL; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stundenzettel.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stundenzettel.java new file mode 100644 index 00000000..5cb7fbec --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Stundenzettel.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Stundenzettel"}, template = "${}") +public class Stundenzettel { + @Adapt(ref = {"Stundenzettel.status"}, template = "${}") + private StundenzettelStatus status; + + @Adapt(ref = {"Stundenzettel.zeit"}, template = "${}") + private ZonedDateTime zeit; + + @Adapt(ref = {"Stundenzettel.abgegebenVonUserId"}, template = "${}") + private Optional abgegebenVonUserId; + + @Adapt(ref = {"Stundenzettel.abgabeDatum"}, template = "${}") + private Optional abgabeDatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelChangeOperation.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelChangeOperation.java new file mode 100644 index 00000000..7cba635b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelChangeOperation.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum StundenzettelChangeOperation { + INVALID, + ABGEGEBEN, + INTERN_GEPRUEFT, + INTERN_ABGESCHLOSSEN; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelEintrag.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelEintrag.java new file mode 100644 index 00000000..8d05c8de --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelEintrag.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"StundenzettelEintrag"}, template = "${}") +public class StundenzettelEintrag { + @Adapt(ref = {"StundenzettelEintrag.uhrzeitVon"}, template = "${}") + private ZonedDateTime uhrzeitVon; + + @Adapt(ref = {"StundenzettelEintrag.uhrzeitBis"}, template = "${}") + private Optional uhrzeitBis; + + @Adapt(ref = {"StundenzettelEintrag.beschreibung"}, template = "${}") + private Optional beschreibung; + + @Adapt(ref = {"StundenzettelEintrag.stunden"}, template = "${}") + private long stunden; + + @Adapt(ref = {"StundenzettelEintrag.pauseOderSonstiges"}, template = "${}") + private StundenzettelProjekt pauseOderSonstiges; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelHistorieEintrag.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelHistorieEintrag.java new file mode 100644 index 00000000..6a51455f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelHistorieEintrag.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"StundenzettelHistorieEintrag"}, template = "${}") +public class StundenzettelHistorieEintrag { + @Adapt(ref = {"StundenzettelHistorieEintrag.bearbeitungsdatum"}, template = "${}") + private ZonedDateTime bearbeitungsdatum; + + @Adapt(ref = {"StundenzettelHistorieEintrag.editorId"}, template = "${}") + private Optional editorId; + + @Adapt(ref = {"StundenzettelHistorieEintrag.editedBy"}, template = "${}") + private Optional editedBy; + + @Adapt(ref = {"StundenzettelHistorieEintrag.monat"}, template = "${}") + private String monat; + + @Adapt(ref = {"StundenzettelHistorieEintrag.jahr"}, template = "${}") + private int jahr; + + @Adapt(ref = {"StundenzettelHistorieEintrag.changeOperation"}, template = "${}") + private String changeOperation; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelProjekt.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelProjekt.java new file mode 100644 index 00000000..a436e6fc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelProjekt.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum StundenzettelProjekt { + PAUSE, + SONSTIGE, + NONE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelStatus.java new file mode 100644 index 00000000..bae441b4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/StundenzettelStatus.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum StundenzettelStatus { + IN_ERFASSUNG, + INTERN_INPRUEFUNG, + INTERN_ABGESCHLOSSEN, + DRITTMITTELABTEILUNG_INPRUEFUNG, + DRITTMITTELABTEILUNG_ABGESCHLOSSEN, + ENDBERICHT_EINGEREICHT, + GEPRUEFT, + FOERDERGEBER_ABGESCHLOSSEN, + ABGESCHLOSSEN; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/TableIdentifierTyp.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/TableIdentifierTyp.java new file mode 100644 index 00000000..a52b2a2a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/TableIdentifierTyp.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum TableIdentifierTyp { + DEFAULT, + USER, + INSTITUT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/TableSetting.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/TableSetting.java new file mode 100644 index 00000000..00c87b77 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/TableSetting.java @@ -0,0 +1,28 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"TableSetting"}, template = "${}") +public class TableSetting extends UISetting { + @Adapt(ref = {"TableSetting.typ"}, template = "${}") + private TableIdentifierTyp typ; + + @Adapt(ref = {"TableSetting.zeigeInaktive"}, template = "${}") + private boolean zeigeInaktive; + + @Adapt(ref = {"TableSetting.zeilenLimit"}, template = "${}") + private int zeilenLimit; + + @Adapt(ref = {"TableSetting.gruppiereNach"}, template = "${}") + private Optional gruppiereNach; + + @Adapt(ref = {"TableSetting.sortiereNach"}, template = "${}") + private Optional sortiereNach; + + @Adapt(ref = {"TableSetting.sortiereDir"}, template = "${}") + private Optional sortiereDir; + + @Adapt(ref = {"TableSetting.isShowColor"}, template = "${}") + private boolean isShowColor; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/TableSettingSpalten.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/TableSettingSpalten.java new file mode 100644 index 00000000..bad9f6ec --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/TableSettingSpalten.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"TableSettingSpalten"}, template = "${}") +public class TableSettingSpalten { + @Adapt(ref = {"TableSettingSpalten.name"}, template = "${}") + private String name; + + @Adapt(ref = {"TableSettingSpalten.istAktiv"}, template = "${}") + private boolean istAktiv; + + @Adapt(ref = {"TableSettingSpalten.breite"}, template = "${}") + private long breite; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Titel.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Titel.java new file mode 100644 index 00000000..eeeff1e5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Titel.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Titel { + NONE, + E1, + E2, + E3, + E4, + E5, + E6, + E7, + E8, + E9, + E10, + E11, + E12, + E13, + E14, + E15, + E16, + E17, + E18, + E19, + E20; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UISetting.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UISetting.java new file mode 100644 index 00000000..4b7c2458 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UISetting.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"UISetting"}, template = "${}") +public class UISetting extends Setting { + @Adapt(ref = {"UISetting.seite"}, template = "${}") + private String seite; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UrlaubEinstellungen.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UrlaubEinstellungen.java new file mode 100644 index 00000000..30aa1cc6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UrlaubEinstellungen.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"UrlaubEinstellungen"}, template = "${}") +public class UrlaubEinstellungen { + @Adapt(ref = {"UrlaubEinstellungen.urlaubsanspruchInStunden"}, template = "${}") + private boolean urlaubsanspruchInStunden; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UrlaubsGenehmigung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UrlaubsGenehmigung.java new file mode 100644 index 00000000..69799154 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UrlaubsGenehmigung.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"UrlaubsGenehmigung"}, template = "${}") +public class UrlaubsGenehmigung { + @Adapt(ref = {"UrlaubsGenehmigung.beantragt"}, template = "${}") + private Optional beantragt; + + @Adapt(ref = {"UrlaubsGenehmigung.genehmigt"}, template = "${}") + private Optional genehmigt; + + @Adapt(ref = {"UrlaubsGenehmigung.geprueft"}, template = "${}") + private Optional geprueft; + + @Adapt(ref = {"UrlaubsGenehmigung.storniert"}, template = "${}") + private Optional storniert; + + @Adapt(ref = {"UrlaubsGenehmigung.status"}, template = "${}") + private Urlaubssstatus status; + + @Adapt(ref = {"UrlaubsGenehmigung.stornierungsStatus"}, template = "${}") + private Stornierungsstatus stornierungsStatus; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Urlaubssstatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Urlaubssstatus.java new file mode 100644 index 00000000..5699adc1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Urlaubssstatus.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Urlaubssstatus { + NONE, + BEANTRAGT, + GEPRUEFT, + PRUEFUNG_ABGELEHNT, + GENEHMIGT, + GENEHMIGUNG_ABGELEHNT; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UserNotification.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UserNotification.java new file mode 100644 index 00000000..c41c7091 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UserNotification.java @@ -0,0 +1,28 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"UserNotification"}, template = "${}") +public class UserNotification { + @Adapt(ref = {"UserNotification.notificationType"}, template = "${}") + private UserNotificationType notificationType; + + @Adapt(ref = {"UserNotification.title"}, template = "${}") + private String title; + + @Adapt(ref = {"UserNotification.message"}, template = "${}") + private String message; + + @Adapt(ref = {"UserNotification.timeStamp"}, template = "${}") + private ZonedDateTime timeStamp; + + @Adapt(ref = {"UserNotification.link"}, template = "${}") + private Optional link; + + @Adapt(ref = {"UserNotification.seen"}, template = "${}") + private boolean seen; + + @Adapt(ref = {"UserNotification.pinned"}, template = "${}") + private boolean pinned; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UserNotificationType.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UserNotificationType.java new file mode 100644 index 00000000..5a07fcd9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/UserNotificationType.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum UserNotificationType { + SUCCESS, + INFO, + WARNING, + DANGER; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Vergabeverordnung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Vergabeverordnung.java new file mode 100644 index 00000000..ff8c2f32 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Vergabeverordnung.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Vergabeverordnung { + VOL_A, + VOB_A, + UVGO_NRW, + UVGO_BUND, + NONE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Vertrag.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Vertrag.java new file mode 100644 index 00000000..acc4bc8b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Vertrag.java @@ -0,0 +1,40 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Vertrag"}, template = "${}") +public class Vertrag { + @Adapt(ref = {"Vertrag.vertragsBeginn"}, template = "${}") + private ZonedDateTime vertragsBeginn; + + @Adapt(ref = {"Vertrag.vertragsEnde"}, template = "${}") + private ZonedDateTime vertragsEnde; + + @Adapt(ref = {"Vertrag.aenderungsvertrag"}, template = "${}") + private boolean aenderungsvertrag; + + @Adapt(ref = {"Vertrag.vertragsStatus"}, template = "${}") + private String vertragsStatus; + + @Adapt(ref = {"Vertrag.kommentar"}, template = "${}") + private List kommentar; + + @Adapt(ref = {"Vertrag.planUmfang"}, template = "${}") + private ZahlenWert planUmfang; + + @Adapt(ref = {"Vertrag.arbeitsstundenProWoche"}, template = "${}") + private Optional arbeitsstundenProWoche; + + @Adapt(ref = {"Vertrag.kuendigungsschutz"}, template = "${}") + private boolean kuendigungsschutz; + + @Adapt(ref = {"Vertrag.vertragsgrundlage"}, template = "${}") + private Optional vertragsgrundlage; + + @Adapt(ref = {"Vertrag.aktion"}, template = "${}") + private Optional aktion; + + @Adapt(ref = {"Vertrag.aktionsDatum"}, template = "${}") + private Optional aktionsDatum; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/VertragStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/VertragStatus.java new file mode 100644 index 00000000..da4d2127 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/VertragStatus.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum VertragStatus { + AKTIV, + PLANUNG, + ABGELAUFEN; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Vertragsgrundlage.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Vertragsgrundlage.java new file mode 100644 index 00000000..48c1557e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Vertragsgrundlage.java @@ -0,0 +1,29 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Vertragsgrundlage { + NONE, + E1, + E2, + E3, + E4, + E5, + E6, + E7, + E8, + E9, + E10, + E11, + E12, + E13, + E14, + E15, + E16, + E17, + E18, + E19, + E20, + E21, + E22, + E23, + E24; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ZahlenTyp.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ZahlenTyp.java new file mode 100644 index 00000000..64f76eb8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ZahlenTyp.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum ZahlenTyp { + EURO, + STUNDE, + PROZENT, + NONE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ZahlenWert.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ZahlenWert.java new file mode 100644 index 00000000..8bb3fd27 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ZahlenWert.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"ZahlenWert"}, template = "${}") +public class ZahlenWert { + @Adapt(ref = {"ZahlenWert.zahlenTyp"}, template = "${}") + private ZahlenTyp zahlenTyp; + + @Adapt(ref = {"ZahlenWert.wert"}, template = "${}") + private long wert; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ZeitlicheVerbuchungskontoZuordnung.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ZeitlicheVerbuchungskontoZuordnung.java new file mode 100644 index 00000000..69de00dc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/ZeitlicheVerbuchungskontoZuordnung.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"ZeitlicheVerbuchungskontoZuordnung"}, template = "${}") +public class ZeitlicheVerbuchungskontoZuordnung { + @Adapt(ref = {"ZeitlicheVerbuchungskontoZuordnung.programmPauschale"}, template = "${}") + private Optional programmPauschale; + + @Adapt(ref = {"ZeitlicheVerbuchungskontoZuordnung.gemeinkostensatz"}, template = "${}") + private Optional gemeinkostensatz; + + @Adapt(ref = {"ZeitlicheVerbuchungskontoZuordnung.startDate"}, template = "${}") + private Optional startDate; + + @Adapt(ref = {"ZeitlicheVerbuchungskontoZuordnung.endDate"}, template = "${}") + private Optional endDate; + + @Adapt(ref = {"ZeitlicheVerbuchungskontoZuordnung.istHauptVerbuchungskonto"}, template = "${}") + private boolean istHauptVerbuchungskonto; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Zulage.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Zulage.java new file mode 100644 index 00000000..62ac766f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Zulage.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Zulage"}, template = "${}") +public class Zulage { + @Adapt(ref = {"Zulage.pspelement"}, template = "${}") + private Optional pspelement; + + @Adapt(ref = {"Zulage.bezeichnung"}, template = "${}") + private Optional bezeichnung; + + @Adapt(ref = {"Zulage.von"}, template = "${}") + private ZonedDateTime von; + + @Adapt(ref = {"Zulage.bis"}, template = "${}") + private ZonedDateTime bis; + + @Adapt(ref = {"Zulage.arbeitgeberbrutto"}, template = "${}") + private Long arbeitgeberbrutto; + + @Adapt(ref = {"Zulage.arbeitnehmerbrutto"}, template = "${}") + private Long arbeitnehmerbrutto; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Zuweisungsart.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Zuweisungsart.java new file mode 100644 index 00000000..75216128 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/adapter/Empty/Zuweisungsart.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco.adapter.empty; + +public enum Zuweisungsart { + KONTO, + STELLENZUWEISUNG, + PLANSTELLE, + SONSTIGES; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/concrete/Placeholder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/concrete/Placeholder.java new file mode 100644 index 00000000..80bf0d71 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/macoco/concrete/Placeholder.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.macoco; + +public class Placeholder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/LanguageInfrastructureConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/LanguageInfrastructureConc.cd new file mode 100644 index 00000000..10e46f1f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/LanguageInfrastructureConc.cd @@ -0,0 +1,8 @@ +classdiagram LanguageInfrastructureConc { + + <> class G1Parser; + <> class G1Traverser; + <> class ASTFooBuilder; + + <> class G1Mill; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/MillOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/MillOut.cd new file mode 100644 index 00000000..9299c9d5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/MillOut.cd @@ -0,0 +1,17 @@ +classdiagram LanguageInfrastructureConc { + + <> class G1Parser; + <> class G1Traverser; + <> class ASTFooBuilder; + + <> class G1Mill { + static void init(); + static void initMe(G1Mill me); + <> G1Parser _G1Parser(); + <> G1Traverser _G1Traverser(); + <> ASTFooBuilder _ASTFooBuilder(); + <> static G1Parser g1Parser(); + <> static G1Traverser g1Traverser(); + <> static ASTFooBuilder aSTFooBuilder(); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/MillRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/MillRef.cd new file mode 100644 index 00000000..27c4eca4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/MillRef.cd @@ -0,0 +1,11 @@ +classdiagram MillRef { + + class MillProduct; + + class Mill { + static void init(); + static void initMe(Mill me); + <> MillProduct _MillProduct(); + <> static MillProduct millProduct(); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/adapter/LanguageInfrastructure/Mill.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/adapter/LanguageInfrastructure/Mill.java new file mode 100644 index 00000000..778f8469 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/adapter/LanguageInfrastructure/Mill.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.mill.adapter.languageinfrastructure; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Mill"}, template = "${}") +public class Mill { + @Adapt(ref = {"Mill.init"}, template = "${}") + public void init() { + } + + @Adapt(ref = {"Mill.initMe"}, template = "${}") + public void initMe(Mill me) { + } + + @Adapt(ref = {"Mill._MillProduct"}, template = "${}") + public MillProduct _MillProduct() { + return null; + } + + @Adapt(ref = {"Mill.millProduct"}, template = "${}") + public MillProduct millProduct() { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/adapter/LanguageInfrastructure/MillProduct.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/adapter/LanguageInfrastructure/MillProduct.java new file mode 100644 index 00000000..049b626c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/adapter/LanguageInfrastructure/MillProduct.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.mill.adapter.languageinfrastructure; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"MillProduct"}, template = "${}") +public class MillProduct { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/ASTFooBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/ASTFooBuilder.java new file mode 100644 index 00000000..c2e219e9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/ASTFooBuilder.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.mill; + +public class ASTFooBuilder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/G1Mill.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/G1Mill.java new file mode 100644 index 00000000..5028e657 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/G1Mill.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.mill; + +public class G1Mill { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/G1Parser.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/G1Parser.java new file mode 100644 index 00000000..2c83ddf4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/G1Parser.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.mill; + +public class G1Parser { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/G1Traverser.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/G1Traverser.java new file mode 100644 index 00000000..a4f36cb9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/mill/concrete/G1Traverser.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.mill; + +public class G1Traverser { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/ObserverRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/ObserverRef.cd new file mode 100644 index 00000000..75a32843 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/ObserverRef.cd @@ -0,0 +1,14 @@ +classdiagram ObserverRef { + + class Observer { + void update(); + } + + class Subject { + void register(Observer o); + void unregister(Observer o); + void notifyObservers(); + } + + association Subject -> (observers) Observer [*] <>; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/adapter/Observer.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/adapter/Observer.java new file mode 100644 index 00000000..e79fe3bd --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/adapter/Observer.java @@ -0,0 +1,11 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.observer; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Observer"}, template = "${}") +public class Observer { + @Adapt(ref = {"Observer.update"}, template = "${}") + public void update() { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/adapter/Subject.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/adapter/Subject.java new file mode 100644 index 00000000..9c68f917 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/adapter/Subject.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.observer; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Subject"}, template = "${}") +public class Subject { + @Adapt(ref = {"Subject.register"}, template = "${}") + public void register(Observer o) { + } + + @Adapt(ref = {"Subject.unregister"}, template = "${}") + public void unregister(Observer o) { + } + + @Adapt(ref = {"Subject.notifyObservers"}, template = "${}") + public void notifyObservers() { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/MutualObserversConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/MutualObserversConc.cd new file mode 100644 index 00000000..0d26ddd4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/MutualObserversConc.cd @@ -0,0 +1,5 @@ +classdiagram MutualObserversConc { + <> class Attacker; + <> class Defender; + association watches [*] Attacker <-> Defender [*]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/MutualObserversOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/MutualObserversOut.cd new file mode 100644 index 00000000..552c8571 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/MutualObserversOut.cd @@ -0,0 +1,18 @@ +classdiagram MutualObserversConc { + + <> class Attacker { + void update(); + void register(Defender o); + void unregister(Defender o); + void notifyObservers(); + + } + <> class Defender { + void update(); + void register(Attacker o); + void unregister(Attacker o); + void notifyObservers(); + } + association watches [*] Attacker (attackers) <-> (defenders) Defender[*]; + +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/concrete/MutualObservers/Attacker.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/concrete/MutualObservers/Attacker.java new file mode 100644 index 00000000..8d0f746c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/concrete/MutualObservers/Attacker.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.observer.mutualobservers.concrete.mutualobservers; + +public class Attacker { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/concrete/MutualObservers/Defender.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/concrete/MutualObservers/Defender.java new file mode 100644 index 00000000..c13b47d5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/observer/mutualObservers/concrete/MutualObservers/Defender.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.observer.mutualobservers.concrete.mutualobservers; + +public class Defender { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/repository/EcommerceDomain.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/repository/EcommerceDomain.cd new file mode 100644 index 00000000..cd57e5eb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/repository/EcommerceDomain.cd @@ -0,0 +1,19 @@ +import java.lang.String; +/* (c) https://github.com/MontiCore/monticore */ + +classdiagram EcommerceDomain { + + <> class Product { + <> String sku; + double price; + } + + <> class Order { + <> long id; + } + + <> class Customer { + <> long id; + <> String email; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/repository/RepositoryOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/repository/RepositoryOut.cd new file mode 100644 index 00000000..e1db2189 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/repository/RepositoryOut.cd @@ -0,0 +1,42 @@ +import java.lang.String; +import java.util.List; +import java.util.Optional; + +classdiagram EcommerceDomain { + <> class Product { + <> String sku; + double price; + } + + <> class Order { + <> long id; + } + + <> class Customer { + <> long id; + <> String email; + } + + <>class ProductRepository { + <> Optional findBySku(String sku); + List findAll(); + Product save(Product product); + <> void removeBySku(String sku); + } + + <>class OrderRepository { + <> Optional findById(long id); + List findAll(); + Order save(Order order); + <> void removeById(long id); + } + + <>class CustomerRepository { + <> Optional findById(long id); + <> Optional findByEmail(String email); + List findAll(); + Customer save(Customer customer); + <> void removeById(long id); + <> void removeByEmail(String email); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/repository/RepositoryRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/repository/RepositoryRef.cd new file mode 100644 index 00000000..b21e2ee2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/repository/RepositoryRef.cd @@ -0,0 +1,16 @@ +import java.util.List; +import java.util.Optional; + +classdiagram RepositoryRef { + + class Entity { + any key; + } + + <> class EntityRepository { + <> Optional findByKey(any key); + List findAll(); + Entity save(Entity entity); + <> void removeByKey(any key); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/TaskManagementRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/TaskManagementRef.cd new file mode 100644 index 00000000..1acdc1e9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/TaskManagementRef.cd @@ -0,0 +1,28 @@ +import java.lang.String; +/* (c) https://github.com/MontiCore/monticore */ + +classdiagram TaskManagementRef { + + class Task { + String title; + String description; + TaskStatus status; + } + + class Member { + String name; + String email; + } + + class Project { + String name; + } + + enum TaskStatus { + Open, InProgress, Done; + } + + association Member -> (assignedTasks) Task [*]; + association Project -> (members) Member [*]; + association Project -> Task [*]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/TicketSystemConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/TicketSystemConc.cd new file mode 100644 index 00000000..d4ce2ed2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/TicketSystemConc.cd @@ -0,0 +1,15 @@ +import java.lang.String; +/* (c) https://github.com/MontiCore/monticore */ + +classdiagram TicketSystemConc { + + <> class Ticket { + <> String summary; + <> String detail; + } + + <> class Workspace { + <> String label; + boolean archived; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/TicketSystemOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/TicketSystemOut.cd new file mode 100644 index 00000000..1589820a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/TicketSystemOut.cd @@ -0,0 +1,29 @@ +import java.lang.String; +/* (c) https://github.com/MontiCore/monticore */ + +classdiagram TicketSystemConc { + + <> class Ticket { + <> String summary; + <> String detail; + TaskStatus status; + } + + <> class Workspace { + <> String label; + boolean archived; + } + + class Member { + String name; + String email; + } + + enum TaskStatus { + Open, InProgress, Done; + } + + association Member -> (assignedTickets) Ticket [*]; + association Workspace -> (members) Member [*]; + association Workspace -> Ticket [*]; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/Member.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/Member.java new file mode 100644 index 00000000..db33b304 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/Member.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.paper_examples.task_management.adapter.ticketsystem; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Member"}, template = "${}") +public class Member { + @Adapt(ref = {"Member.name"}, template = "${}") + private String name; + + @Adapt(ref = {"Member.email"}, template = "${}") + private String email; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/Project.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/Project.java new file mode 100644 index 00000000..1a546671 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/Project.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.paper_examples.task_management.adapter.ticketsystem; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Project"}, template = "${}") +public class Project { + @Adapt(ref = {"Project.name"}, template = "${}") + private String name; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/Task.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/Task.java new file mode 100644 index 00000000..d850a279 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/Task.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.paper_examples.task_management.adapter.ticketsystem; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Task"}, template = "${}") +public class Task { + @Adapt(ref = {"Task.title"}, template = "${}") + private String title; + + @Adapt(ref = {"Task.description"}, template = "${}") + private String description; + + @Adapt(ref = {"Task.status"}, template = "${}") + private TaskStatus status; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/TaskStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/TaskStatus.java new file mode 100644 index 00000000..069fa28a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/adapter/TicketSystem/TaskStatus.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.paper_examples.task_management.adapter.ticketsystem; + +public enum TaskStatus { + Open, + InProgress, + Done; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/concrete/Ticket.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/concrete/Ticket.java new file mode 100644 index 00000000..013d6232 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/concrete/Ticket.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.paper_examples.task_management; + +public class Ticket { + private String summary; + + private String detail; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/concrete/Workspace.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/concrete/Workspace.java new file mode 100644 index 00000000..a73696df --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/paper-examples/task-management/concrete/Workspace.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.paper_examples.task_management; + +public class Workspace { + private String label; + + private boolean archived; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/repository/DomainModel.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/repository/DomainModel.cd new file mode 100644 index 00000000..e1bde702 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/repository/DomainModel.cd @@ -0,0 +1,17 @@ +import java.lang.String; + + classdiagram DomainModel { + <> class Employee { + <> String id; + <> String taxId; + String firstName; + String lastName; + int number; + int salary; + } + + <> class Department { + String managerName; + <> int depId; + } + } diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/repository/RepositoryOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/repository/RepositoryOut.cd new file mode 100644 index 00000000..c0aa6ce4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/repository/RepositoryOut.cd @@ -0,0 +1,36 @@ +import java.lang.String; +import java.util.List; +import java.util.Optional; + +classdiagram DomainModel { + <> class Employee { + <> String id; + <> String taxId; + String firstName; + String lastName; + int number; + int salary; + } + + <> class Department { + String managerName; + <> int depId; + } + + <>class DepartmentRepository { + <> Optional findByDepId(int depId); + List findAll(); + Department save(Department department); + <> void removeByDepId(int depId); + + } + + <>class EmployeeRepository { + <> Optional findById(String id); + <> Optional findByTaxId(String taxId); + List findAll(); + Employee save(Employee employee); + <> void removeById(String id); + <> void removeByTaxId(String taxId); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/repository/RepositoryRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/repository/RepositoryRef.cd new file mode 100644 index 00000000..4d2bb87c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/repository/RepositoryRef.cd @@ -0,0 +1,16 @@ +import java.util.List; +import java.util.Optional; + +classdiagram RepositoryRef { + + class Entity { + any id; + } + + <> class EntityRepository { + <> Optional findById(any id); + List findAll(); + Entity save(Entity entity); + <> void removeById(any id); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/StaticDelegatorConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/StaticDelegatorConc.cd new file mode 100644 index 00000000..7c4c7428 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/StaticDelegatorConc.cd @@ -0,0 +1,8 @@ +classdiagram StaticDelegatorConc { + + <> class MyLanguageMill { + <> static void foo(); + <> static int getId(); + <> static void doSomething(); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/StaticDelegatorOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/StaticDelegatorOut.cd new file mode 100644 index 00000000..74b6676c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/StaticDelegatorOut.cd @@ -0,0 +1,12 @@ +classdiagram StaticDelegatorConc { + + <> class MyLanguageMill { + <> static void foo(); + <> static int getId(); + <> static void doSomething(); + + <> void _foo(); + <> int _getId(); + <> void _doSomething(); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/StaticDelegatorRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/StaticDelegatorRef.cd new file mode 100644 index 00000000..f53adaf4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/StaticDelegatorRef.cd @@ -0,0 +1,7 @@ +classdiagram StaticDelegatorRef { + + class StaticDelegator { + <> any _method(); + static any method(); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/adapter/StaticDelegator/StaticDelegator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/adapter/StaticDelegator/StaticDelegator.java new file mode 100644 index 00000000..9cd1cbeb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/adapter/StaticDelegator/StaticDelegator.java @@ -0,0 +1,17 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.staticdelegator.adapter.staticdelegator; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"StaticDelegator"}, template = "${}") +public class StaticDelegator { + @Adapt(ref = {"StaticDelegator._method"}, template = "${}") + public Object _method() { + return null; + } + + @Adapt(ref = {"StaticDelegator.method"}, template = "${}") + public Object method() { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsConc.cd new file mode 100644 index 00000000..a914554f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsConc.cd @@ -0,0 +1,8 @@ +classdiagram InstanceMethodExistsConc { + + <> class MyLanguageMill { + <> int _foo; + <> int _getId; + <> boolean _doSomething; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsOut.cd new file mode 100644 index 00000000..cfdb9ab9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/InstanceMethodExistsOut.cd @@ -0,0 +1,12 @@ +classdiagram InstanceMethodExistsConc { + + <> class MyLanguageMill { + <> int _foo; + <> int _getId; + <> boolean _doSomething; + + <> static int foo; + <> static int getId; + <> static boolean doSomething; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/StaticDelegatorRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/StaticDelegatorRef.cd new file mode 100644 index 00000000..9b9d2d65 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/StaticDelegatorRef.cd @@ -0,0 +1,12 @@ +classdiagram StaticDelegatorRef { + + /* + * Because there is not yet a "method forEach method" completion implementation, we test the + * same pattern with attributes. + */ + + class StaticDelegator { + <> any _method; + static any method; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/StaticExistsConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/StaticExistsConc.cd new file mode 100644 index 00000000..f09aab16 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/StaticExistsConc.cd @@ -0,0 +1,8 @@ +classdiagram StaticExistsConc { + + <> class MyLanguageMill { + <> static int foo; + <> static int getId; + <> static boolean doSomething; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/StaticExistsOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/StaticExistsOut.cd new file mode 100644 index 00000000..46491610 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/StaticExistsOut.cd @@ -0,0 +1,12 @@ +classdiagram StaticExistsConc { + + <> class MyLanguageMill { + <> static int foo; + <> static int getId; + <> static boolean doSomething; + + <> int _foo; + <> int _getId; + <> boolean _doSomething; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/adapter/InstanceMethodExists/StaticDelegator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/adapter/InstanceMethodExists/StaticDelegator.java new file mode 100644 index 00000000..10c9da19 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/adapter/InstanceMethodExists/StaticDelegator.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.staticdelegator.attrworkaround.adapter.instancemethodexists; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"StaticDelegator"}, template = "${}") +public class StaticDelegator { + @Adapt(ref = {"StaticDelegator._method"}, template = "${}") + private Object _method; + + @Adapt(ref = {"StaticDelegator.method"}, template = "${}") + private Object method; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/adapter/StaticExists/StaticDelegator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/adapter/StaticExists/StaticDelegator.java new file mode 100644 index 00000000..80e73a42 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/adapter/StaticExists/StaticDelegator.java @@ -0,0 +1,12 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.staticdelegator.attrworkaround.adapter.staticexists; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"StaticDelegator"}, template = "${}") +public class StaticDelegator { + @Adapt(ref = {"StaticDelegator._method"}, template = "${}") + private Object _method; + + @Adapt(ref = {"StaticDelegator.method"}, template = "${}") + private Object method; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/concrete/MyLanguageMill.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/concrete/MyLanguageMill.java new file mode 100644 index 00000000..e6810e2a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/attrWorkaround/concrete/MyLanguageMill.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.staticdelegator.attrworkaround; + +public class MyLanguageMill { + private int foo; + + private int getId; + + private boolean doSomething; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/concrete/MyLanguageMill.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/concrete/MyLanguageMill.java new file mode 100644 index 00000000..a0e7edcd --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/staticDelegator/concrete/MyLanguageMill.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.staticdelegator; + +public class MyLanguageMill { + public void foo() { + } + + public int getId() { + return 0; + } + + public void doSomething() { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesConc.cd new file mode 100644 index 00000000..fb4256b0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesConc.cd @@ -0,0 +1,5 @@ +classdiagram TransitiveDependenciesConc { + + <> class Employee; + <> class Department; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesOut.cd new file mode 100644 index 00000000..15e1b714 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesOut.cd @@ -0,0 +1,11 @@ +classdiagram TransitiveDependenciesConc { + + <> class Employee; + <> class Department; + + <> class EmployeeBuilder; + <> class DepartmentBuilder; + + <> class EmployeeBuilderFactory; + <> class DepartmentBuilderFactory; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesRef.cd new file mode 100644 index 00000000..dfdf85e6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesRef.cd @@ -0,0 +1,8 @@ +classdiagram TransitiveDependenciesRef { + + class DataClass; + + <> class DataClassBuilder; + + <> class DataClassBuilderFactory; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesSwappedOrderRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesSwappedOrderRef.cd new file mode 100644 index 00000000..94091796 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/TransitiveDependenciesSwappedOrderRef.cd @@ -0,0 +1,10 @@ +classdiagram TransitiveDependenciesRef { + + <> class DataClassBuilderFactory; + + class DataClass; + + <> class DataClassBuilder; + + +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/adapter/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/adapter/DataClass.java new file mode 100644 index 00000000..1d4e22c2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/adapter/DataClass.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.transitivedependencies; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/adapter/DataClassBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/adapter/DataClassBuilder.java new file mode 100644 index 00000000..765c3fab --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/adapter/DataClassBuilder.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.transitivedependencies; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClassBuilder"}, template = "${}") +public class DataClassBuilder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/adapter/TransitiveDependencies/DataClassBuilderFactory.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/adapter/TransitiveDependencies/DataClassBuilderFactory.java new file mode 100644 index 00000000..fd814d0c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/adapter/TransitiveDependencies/DataClassBuilderFactory.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.transitivedependencies.adapter.transitivedependencies; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClassBuilderFactory"}, template = "${}") +public class DataClassBuilderFactory { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/concrete/Department.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/concrete/Department.java new file mode 100644 index 00000000..c3f8f8aa --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/concrete/Department.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.transitivedependencies; + +public class Department { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/concrete/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/concrete/Employee.java new file mode 100644 index 00000000..00de4a9c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/transitiveDependencies/concrete/Employee.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.transitivedependencies; + +public class Employee { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/VisitorConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/VisitorConc.cd new file mode 100644 index 00000000..e3f35685 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/VisitorConc.cd @@ -0,0 +1,9 @@ +classdiagram VisitorConc { + + <> interface Node; + + // TODO remove incarnation mappings once <> is implemented + <> class RootNode implements Node; + <> class InnerNode implements Node; + <> class LeafNode implements Node; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/VisitorOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/VisitorOut.cd new file mode 100644 index 00000000..e9a246d1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/VisitorOut.cd @@ -0,0 +1,17 @@ +classdiagram VisitorConc { + + <> interface Node { + void accept(NodeVisitor visitor); + } + + <> class RootNode implements Node; + <> class InnerNode implements Node; + <> class LeafNode implements Node; + + <> interface NodeVisitor { + void visit(Node node); + <> void visit(RootNode rootNode); + <> void visit(InnerNode innerNode); + <> void visit(LeafNode leafNode); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/VisitorRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/VisitorRef.cd new file mode 100644 index 00000000..c22ac725 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/VisitorRef.cd @@ -0,0 +1,14 @@ +classdiagram VisitorRef { + + interface Visitable { + void accept(VisitableVisitor visitor); + } + + // TODO use <> here once it is implemented + class ConcreteVisitable implements Visitable; + + <> interface VisitableVisitor { + void visit(Visitable visitable); + <> void visit(ConcreteVisitable concreteVisitable); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/adapter/Visitor/ConcreteVisitable.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/adapter/Visitor/ConcreteVisitable.java new file mode 100644 index 00000000..2a1415ac --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/adapter/Visitor/ConcreteVisitable.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.visitor.adapter.visitor; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"ConcreteVisitable"}, template = "${}") +public class ConcreteVisitable { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/adapter/Visitor/Visitable.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/adapter/Visitor/Visitable.java new file mode 100644 index 00000000..ed5ab0e8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/adapter/Visitor/Visitable.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.visitor.adapter.visitor; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Visitable"}, template = "${}") +public interface Visitable { + @Adapt(ref = {"Visitable.accept"}, template = "${}") + void accept(VisitableVisitor visitor); + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/adapter/Visitor/VisitableVisitor.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/adapter/Visitor/VisitableVisitor.java new file mode 100644 index 00000000..c159765b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/adapter/Visitor/VisitableVisitor.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.visitor.adapter.visitor; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"VisitableVisitor"}, template = "${}") +public interface VisitableVisitor { + @Adapt(ref = {"VisitableVisitor.visit(Visitable)"}, template = "${}") + void visit(Visitable visitable); + + @Adapt(ref = {"VisitableVisitor.visit(ConcreteVisitable)"}, template = "${}") + void visit(ConcreteVisitable concreteVisitable); + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/InnerNode.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/InnerNode.java new file mode 100644 index 00000000..887c0390 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/InnerNode.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.visitor; + +public class InnerNode { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/LeafNode.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/LeafNode.java new file mode 100644 index 00000000..e3d3cc18 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/LeafNode.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.visitor; + +public class LeafNode { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/Node.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/Node.java new file mode 100644 index 00000000..37e3b697 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/Node.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.visitor; + +public interface Node { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/RootNode.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/RootNode.java new file mode 100644 index 00000000..aa3425cb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/evaluation/visitor/concrete/RootNode.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.evaluation.visitor; + +public class RootNode { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/HelperConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/HelperConc.cd new file mode 100644 index 00000000..5d6f1a7f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/HelperConc.cd @@ -0,0 +1,12 @@ +classdiagram HelperConc { + + class A { + } + class B { + } + <> class C { + } + <> class D { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/HelperOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/HelperOut.cd new file mode 100644 index 00000000..a72bc4a3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/HelperOut.cd @@ -0,0 +1,10 @@ +classdiagram HelperConc { + class A; + class B; + <> class C; + <> class D; + + association A (roleNameLeft) <-> (roleNameRight_B) B; + association A (roleNameLeft) <-> (roleNameRight_C) C; + association A (roleNameLeft) <-> (roleNameRight_D) D; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/HelperRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/HelperRef.cd new file mode 100644 index 00000000..ee0c99a6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/HelperRef.cd @@ -0,0 +1,7 @@ +classdiagram HelperRef { + class A { + } + class B { + } + association A (roleNameLeft) <-> (roleNameRight) B; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/adapter/A.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/adapter/A.java new file mode 100644 index 00000000..8312f6e0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/adapter/A.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.helper; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"A"}, template = "${}") +public class A { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/adapter/B.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/adapter/B.java new file mode 100644 index 00000000..7731ee20 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/adapter/B.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.helper; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"B"}, template = "${}") +public class B { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/concrete/B.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/concrete/B.java new file mode 100644 index 00000000..e5fbdd1e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/concrete/B.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.helper; + +public class B { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/concrete/C.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/concrete/C.java new file mode 100644 index 00000000..663dea95 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/concrete/C.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.helper; + +public class C { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/concrete/D.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/concrete/D.java new file mode 100644 index 00000000..ad52eb30 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/helper/concrete/D.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.helper; + +public class D { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeInheritanceConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeInheritanceConc.cd new file mode 100644 index 00000000..0027167c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeInheritanceConc.cd @@ -0,0 +1,5 @@ +classdiagram AttributeInheritanceConc { + class Teacher { + int number; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeInheritanceOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeInheritanceOut.cd new file mode 100644 index 00000000..0e71630b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeInheritanceOut.cd @@ -0,0 +1,7 @@ +classdiagram AttributeInheritanceConc { + class Person { + int number; + } + + class Teacher extends Person; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeInheritanceRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeInheritanceRef.cd new file mode 100644 index 00000000..dbe0aa16 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeInheritanceRef.cd @@ -0,0 +1,7 @@ +classdiagram AttributeInheritanceRef { + class Person { + int number; + } + class Teacher extends Person { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeTypeMismatchConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeTypeMismatchConc.cd new file mode 100644 index 00000000..70d8b019 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeTypeMismatchConc.cd @@ -0,0 +1,5 @@ +classdiagram AttributeTypeMismatchConc { + class Teacher { + double number; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeTypeMismatchRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeTypeMismatchRef.cd new file mode 100644 index 00000000..0b063677 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/AttributeTypeMismatchRef.cd @@ -0,0 +1,7 @@ +classdiagram AttributeTypeMismatchRef { + class Person { + int number; + } + class Teacher extends Person { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/MissingInheritanceConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/MissingInheritanceConc.cd new file mode 100644 index 00000000..c40ed444 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/MissingInheritanceConc.cd @@ -0,0 +1,4 @@ +classdiagram MissingInheritanceConc { + class Teacher { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/MissingInheritanceRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/MissingInheritanceRef.cd new file mode 100644 index 00000000..663eab31 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/MissingInheritanceRef.cd @@ -0,0 +1,6 @@ +classdiagram MissingInheritanceRef { + class Person { + } + class Teacher extends Person { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/adapter/Person.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/adapter/Person.java new file mode 100644 index 00000000..3c2cc8e1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/adapter/Person.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.inheritance; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Person"}, template = "${}") +public class Person { + @Adapt(ref = {"Person.number"}, template = "${}") + private int number; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/adapter/Teacher.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/adapter/Teacher.java new file mode 100644 index 00000000..c60c76a7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/adapter/Teacher.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.inheritance; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Teacher"}, template = "${}") +public class Teacher extends Person { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/concrete/Teacher.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/concrete/Teacher.java new file mode 100644 index 00000000..cbdaf4ee --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/inheritance/concrete/Teacher.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.inheritance; + +public class Teacher { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/Reference.cd new file mode 100644 index 00000000..8e3b88c3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/Reference.cd @@ -0,0 +1,8 @@ +classdiagram Reference { + class Account { + void withdraw(int amount); + void deposit(int amount); + void transfer(int amount, Account account); + int getBalance(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/adapter/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/adapter/Account.java new file mode 100644 index 00000000..63ea126d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/adapter/Account.java @@ -0,0 +1,24 @@ +package de.monticore.codeAdaption.cdconcretization.methods.basic; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Account"}, template = "${}") +public class Account { + @Adapt(ref = {"Account.withdraw"}, template = "${}") + public void withdraw(int amount) { + } + + @Adapt(ref = {"Account.deposit"}, template = "${}") + public void deposit(int amount) { + } + + @Adapt(ref = {"Account.transfer"}, template = "${}") + public void transfer(int amount, Account account) { + } + + @Adapt(ref = {"Account.getBalance"}, template = "${}") + public int getBalance() { + return 0; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/ClassEmptyConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/ClassEmptyConc.cd new file mode 100644 index 00000000..cf9318f0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/ClassEmptyConc.cd @@ -0,0 +1,3 @@ +classdiagram MethodMissingConc { + class Account; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/ClassMissingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/ClassMissingConc.cd new file mode 100644 index 00000000..4edd8558 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/ClassMissingConc.cd @@ -0,0 +1,3 @@ +classdiagram ClassMissingConc { + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MethodInSuperClassConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MethodInSuperClassConc.cd new file mode 100644 index 00000000..a37f9ecf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MethodInSuperClassConc.cd @@ -0,0 +1,10 @@ +classdiagram MethodInSuperClassConc { + class AccountBase { + void withdraw(int amount); + void deposit(int amount); + void transfer(int amount, AccountBase account); + int getBalance(); + } + + class Account extends AccountBase; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MethodInSuperClassOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MethodInSuperClassOut.cd new file mode 100644 index 00000000..e0244180 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MethodInSuperClassOut.cd @@ -0,0 +1,13 @@ +classdiagram MethodInSuperClassConc { + class AccountBase { + void withdraw(int amount); + void deposit(int amount); + void transfer(int amount, AccountBase account); + int getBalance(); + } + + class Account extends AccountBase { + // The signature in AccountBase is not enough to serve as incarnation of the reference method + void transfer(int amount, Account account); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MethodMissingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MethodMissingConc.cd new file mode 100644 index 00000000..37ce1c4a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MethodMissingConc.cd @@ -0,0 +1,7 @@ +classdiagram MethodMissingConc { + class Account { + void withdraw(int amount); + void deposit(int amount); + void transfer(int amount, Account account); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MultipleMethodsMissingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MultipleMethodsMissingConc.cd new file mode 100644 index 00000000..cbfe1aea --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/MultipleMethodsMissingConc.cd @@ -0,0 +1,6 @@ +classdiagram MultipleMethodsMissingConc { + class Account { + void withdraw(int amount); + void deposit(int amount); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/WrongSignatureConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/WrongSignatureConc.cd new file mode 100644 index 00000000..bf8efcf3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/WrongSignatureConc.cd @@ -0,0 +1,6 @@ +classdiagram WrongSignatureConc { + class Account { + void withdraw(double amount); + void deposit(double amount); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/WrongSignatureOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/WrongSignatureOut.cd new file mode 100644 index 00000000..acf22e0b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/WrongSignatureOut.cd @@ -0,0 +1,10 @@ +classdiagram WrongSignatureConc { + class Account { + void withdraw(double amount); + void deposit(double amount); + void withdraw(int amount); + void deposit(int amount); + void transfer(int amount, Account account); + int getBalance(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/ClassEmpty/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/ClassEmpty/Account.java new file mode 100644 index 00000000..b7711ad3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/ClassEmpty/Account.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.basic.valid.concrete.classempty; + +public class Account { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MethodInSuperClass/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MethodInSuperClass/Account.java new file mode 100644 index 00000000..a73b0a3c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MethodInSuperClass/Account.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.basic.valid.concrete.methodinsuperclass; + +public class Account extends AccountBase { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MethodInSuperClass/AccountBase.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MethodInSuperClass/AccountBase.java new file mode 100644 index 00000000..048de4c9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MethodInSuperClass/AccountBase.java @@ -0,0 +1,17 @@ +package de.monticore.codeAdaption.cdconcretization.methods.basic.valid.concrete.methodinsuperclass; + +public class AccountBase { + public void withdraw(int amount) { + } + + public void deposit(int amount) { + } + + public void transfer(int amount, AccountBase account) { + } + + public int getBalance() { + return 0; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MethodMissing/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MethodMissing/Account.java new file mode 100644 index 00000000..2b5cfecf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MethodMissing/Account.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.cdconcretization.methods.basic.valid.concrete.methodmissing; + +public class Account { + public void withdraw(int amount) { + } + + public void deposit(int amount) { + } + + public void transfer(int amount, Account account) { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MultipleMethodsMissing/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MultipleMethodsMissing/Account.java new file mode 100644 index 00000000..2453ba82 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/MultipleMethodsMissing/Account.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.methods.basic.valid.concrete.multiplemethodsmissing; + +public class Account { + public void withdraw(int amount) { + } + + public void deposit(int amount) { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/WrongSignature/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/WrongSignature/Account.java new file mode 100644 index 00000000..16f11f17 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/basic/valid/concrete/WrongSignature/Account.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.methods.basic.valid.concrete.wrongsignature; + +public class Account { + public void withdraw(double amount) { + } + + public void deposit(double amount) { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeConc.cd new file mode 100644 index 00000000..75a16f5b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeConc.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram ForEachAttributeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeDifferentReturnTypeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeDifferentReturnTypeConc.cd new file mode 100644 index 00000000..a54aa0dc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeDifferentReturnTypeConc.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram ForEachAttributeDifferentReturnTypeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeDifferentReturnTypeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeDifferentReturnTypeOut.cd new file mode 100644 index 00000000..693e3e9a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeDifferentReturnTypeOut.cd @@ -0,0 +1,15 @@ +import java.lang.String; + +classdiagram ForEachAttributeDifferentReturnTypeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + + <> boolean isFirstNameModified(); + <> boolean isLastNameModified(); + <> boolean isNumberModified(); + <> boolean isSalaryModified(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeDifferentReturnTypeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeDifferentReturnTypeRef.cd new file mode 100644 index 00000000..4f0a0057 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeDifferentReturnTypeRef.cd @@ -0,0 +1,8 @@ + +classdiagram ForEachAttributeDifferentReturnTypeRef { + class DataClass { + any attribute; + + <> boolean isAttributeModified(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeMultipleParametersConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeMultipleParametersConc.cd new file mode 100644 index 00000000..8c26d335 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeMultipleParametersConc.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram ForEachAttributeMultipleParametersConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeMultipleParametersOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeMultipleParametersOut.cd new file mode 100644 index 00000000..3fdd20c4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeMultipleParametersOut.cd @@ -0,0 +1,19 @@ +import java.lang.String; + +classdiagram ForEachAttributeMultipleParametersConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + + <> + void updateFirstName(String firstName, String changedBy); + <> + void updateLastName(String lastName, String changedBy); + <> + void updateNumber(int number, String changedBy); + <> + void updateSalary(int salary, String changedBy); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeMultipleParametersRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeMultipleParametersRef.cd new file mode 100644 index 00000000..49e9de0a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeMultipleParametersRef.cd @@ -0,0 +1,9 @@ +import java.lang.String; + +classdiagram ForEachAttributeMultipleParametersRef { + class DataClass { + any attribute; + // the first parameter is adapted to the attribute and the second always stays the same + <> void updateAttribute(any attribute, String changedBy); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeOut.cd new file mode 100644 index 00000000..053fb7bc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeOut.cd @@ -0,0 +1,17 @@ +import java.lang.String; + +classdiagram ForEachAttributeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + class Builder { + <> Builder firstName(String firstName); + <> Builder lastName(String lastName); + <> Builder number(int number); + <> Builder salary(int salary); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeRef.cd new file mode 100644 index 00000000..f3849837 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeRef.cd @@ -0,0 +1,12 @@ + +classdiagram ForEachAttributeRef { + class DataClass { + any attribute; + } + + class Builder { + // Incarnations will have the same name as the referenced attribute incarnations by convention + // because the referenced attribute has the same name as the annotated attribute! + <> Builder attribute(any attribute); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeClassMIConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeClassMIConc.cd new file mode 100644 index 00000000..7f9af6f2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeClassMIConc.cd @@ -0,0 +1,15 @@ +import java.lang.String; + +classdiagram ForEachAttributeSameReturnTypeClassMIConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + <> String managerName; + <> int depId; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeClassMIOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeClassMIOut.cd new file mode 100644 index 00000000..d54467f2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeClassMIOut.cd @@ -0,0 +1,23 @@ +import java.lang.String; + +classdiagram ForEachAttributeSameReturnTypeClassMIConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + // added methods + <> String getFirstName(); + <> String getLastName(); + <> int getNumber(); + <> int getSalary(); + } + + <> class Department { + <> String managerName; + <> int depId; + // added methods + <> String getManagerName(); + <> int getDepId(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeConc.cd new file mode 100644 index 00000000..9b099c4a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeConc.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram ForEachAttributeSameReturnTypeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeOut.cd new file mode 100644 index 00000000..a786ac1c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeOut.cd @@ -0,0 +1,15 @@ +import java.lang.String; + +classdiagram ForEachAttributeSameReturnTypeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + + <> String getFirstName(); + <> String getLastName(); + <> int getNumber(); + <> int getSalary(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeRef.cd new file mode 100644 index 00000000..d154c0e9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachAttributeSameReturnTypeRef.cd @@ -0,0 +1,7 @@ + +classdiagram ForEachAttributeSameReturnTypeRef { + class DataClass { + any attribute; + <> any getAttribute(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeConc.cd new file mode 100644 index 00000000..51ff6e6b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeConc.cd @@ -0,0 +1,5 @@ +classdiagram ForEachTypeSameReturnTypeConc { + <> class HandshakeMessage; + <> class DataMessage; + <> class AckMessage; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeNoNameMatchOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeNoNameMatchOut.cd new file mode 100644 index 00000000..f2ab72a0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeNoNameMatchOut.cd @@ -0,0 +1,11 @@ +classdiagram ForEachTypeSameReturnTypeConc { + <> class HandshakeMessage; + <> class DataMessage; + <> class AckMessage; + + class MessageBus { + <> void send(HandshakeMessage handshakeMessage); + <> void send(DataMessage dataMessage); + <> void send(AckMessage ackMessage); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeNoNameMatchRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeNoNameMatchRef.cd new file mode 100644 index 00000000..70d3ab56 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeNoNameMatchRef.cd @@ -0,0 +1,7 @@ +classdiagram ForEachTypeSameParameterTypeNoNameMatchRef { + class Message; + + class MessageBus { + <> void send(Message message); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeOut.cd new file mode 100644 index 00000000..11c64bb9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeOut.cd @@ -0,0 +1,11 @@ +classdiagram ForEachTypeSameReturnTypeConc { + <> class HandshakeMessage; + <> class DataMessage; + <> class AckMessage; + + class MessageBus { + <> void sendHandshakeMessage(HandshakeMessage handshakeMessage); + <> void sendDataMessage(DataMessage dataMessage); + <> void sendAckMessage(AckMessage ackMessage); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeRef.cd new file mode 100644 index 00000000..16e00859 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameParameterTypeRef.cd @@ -0,0 +1,7 @@ +classdiagram ForEachTypeSameReturnTypeRef { + class Message; + + class MessageBus { + <> void sendMessage(Message message); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeConc.cd new file mode 100644 index 00000000..aef1bf4d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeConc.cd @@ -0,0 +1,5 @@ +classdiagram ForEachTypeSameReturnTypeConc { + <> class EmployeeBuilder; + <> class DepartmentBuilder; + <> class CompanyBuilder; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeNoNameMatchOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeNoNameMatchOut.cd new file mode 100644 index 00000000..015cba1a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeNoNameMatchOut.cd @@ -0,0 +1,11 @@ +classdiagram ForEachTypeSameReturnTypeConc { + <> class EmployeeBuilder; + <> class DepartmentBuilder; + <> class CompanyBuilder; + + class Mill { + <> EmployeeBuilder create_EmployeeBuilder(); + <> DepartmentBuilder create_DepartmentBuilder(); + <> CompanyBuilder create_CompanyBuilder(); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeNoNameMatchRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeNoNameMatchRef.cd new file mode 100644 index 00000000..7fd3ef7a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeNoNameMatchRef.cd @@ -0,0 +1,9 @@ +classdiagram ForEachTypeSameReturnTypeNoNameMatchRef { + class Builder; + + class Mill { + // we intentionally not use 'Builder' as infix of the method name here, to demonstrate that + // the tools needs to add a suffix to the method for each type if it cannot adapt the name + <> Builder create(); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeOut.cd new file mode 100644 index 00000000..b1784a33 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeOut.cd @@ -0,0 +1,11 @@ +classdiagram ForEachTypeSameReturnTypeConc { + <> class EmployeeBuilder; + <> class DepartmentBuilder; + <> class CompanyBuilder; + + class Mill { + <> EmployeeBuilder employeeBuilder(); + <> DepartmentBuilder departmentBuilder(); + <> CompanyBuilder companyBuilder(); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeRef.cd new file mode 100644 index 00000000..f80c8709 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/ForEachTypeSameReturnTypeRef.cd @@ -0,0 +1,7 @@ +classdiagram ForEachTypeSameReturnTypeRef { + class Builder; + + class Mill { + <> Builder builder(); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/DataClass.java new file mode 100644 index 00000000..0067e23c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/DataClass.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { + @Adapt(ref = {"DataClass.attribute"}, template = "${}") + private Object attribute; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachAttribute/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachAttribute/Builder.java new file mode 100644 index 00000000..8a62db25 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachAttribute/Builder.java @@ -0,0 +1,12 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachattribute; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}") +public class Builder { + @Adapt(ref = {"Builder.attribute"}, template = "${}") + public Builder attribute(Object attribute) { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachAttributeDifferentReturnType/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachAttributeDifferentReturnType/DataClass.java new file mode 100644 index 00000000..3e09e6bc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachAttributeDifferentReturnType/DataClass.java @@ -0,0 +1,15 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachattributedifferentreturntype; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { + @Adapt(ref = {"DataClass.attribute"}, template = "${}") + private Object attribute; + + @Adapt(ref = {"DataClass.isAttributeModified"}, template = "${}") + public boolean isAttributeModified() { + return false; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachAttributeMultipleParameters/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachAttributeMultipleParameters/DataClass.java new file mode 100644 index 00000000..58f95f11 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachAttributeMultipleParameters/DataClass.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachattributemultipleparameters; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { + @Adapt(ref = {"DataClass.attribute"}, template = "${}") + private Object attribute; + + @Adapt(ref = {"DataClass.updateAttribute"}, template = "${}") + public void updateAttribute(Object attribute, String changedBy) { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachTypeSameParameterType/Message.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachTypeSameParameterType/Message.java new file mode 100644 index 00000000..8df97281 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachTypeSameParameterType/Message.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachtypesameparametertype; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Message"}, template = "${}") +public class Message { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachTypeSameParameterType/MessageBus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachTypeSameParameterType/MessageBus.java new file mode 100644 index 00000000..42127968 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachTypeSameParameterType/MessageBus.java @@ -0,0 +1,11 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachtypesameparametertype; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"MessageBus"}, template = "${}") +public class MessageBus { + @Adapt(ref = {"MessageBus.sendMessage"}, template = "${}") + public void sendMessage(Message message) { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachTypeSameReturnType/Mill.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachTypeSameReturnType/Mill.java new file mode 100644 index 00000000..1a6bd361 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/adapter/ForEachTypeSameReturnType/Mill.java @@ -0,0 +1,12 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach.adapter.foreachtypesamereturntype; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Mill"}, template = "${}") +public class Mill { + @Adapt(ref = {"Mill.builder"}, template = "${}") + public Builder builder() { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/concrete/CompanyBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/concrete/CompanyBuilder.java new file mode 100644 index 00000000..10852c78 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/concrete/CompanyBuilder.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach; + +public class CompanyBuilder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/concrete/DepartmentBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/concrete/DepartmentBuilder.java new file mode 100644 index 00000000..8494ee19 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/concrete/DepartmentBuilder.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach; + +public class DepartmentBuilder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/concrete/EmployeeBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/concrete/EmployeeBuilder.java new file mode 100644 index 00000000..26e39252 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/forEach/concrete/EmployeeBuilder.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.foreach; + +public class EmployeeBuilder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterAndReturnTypeMIConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterAndReturnTypeMIConc.cd new file mode 100644 index 00000000..70c5b808 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterAndReturnTypeMIConc.cd @@ -0,0 +1,8 @@ +classdiagram ParameterAndReturnTypeMIConc { + + <> class PersonalAccount; + <> class BusinessAccount; + + <> class NormalTransaction; + <> class InstantTransaction; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterAndReturnTypeMIOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterAndReturnTypeMIOut.cd new file mode 100644 index 00000000..81d0ad23 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterAndReturnTypeMIOut.cd @@ -0,0 +1,22 @@ +classdiagram ParameterAndReturnTypeMIConc { + + <> class PersonalAccount; + <> class BusinessAccount; + + <> class NormalTransaction; + <> class InstantTransaction; + + class Bank { + <> void createPersonalAccount(PersonalAccount personalAccount); + <> void createBusinessAccount(BusinessAccount businessAccount); + <> NormalTransaction transfer_NormalTransaction(PersonalAccount from, PersonalAccount to, int amount); + <> NormalTransaction transfer_NormalTransaction(PersonalAccount from, BusinessAccount to, int amount); + <> NormalTransaction transfer_NormalTransaction(BusinessAccount from, PersonalAccount to, int amount); + <> NormalTransaction transfer_NormalTransaction(BusinessAccount from, BusinessAccount to, int amount); + + <> InstantTransaction transfer_InstantTransaction(PersonalAccount from, PersonalAccount to, int amount); + <> InstantTransaction transfer_InstantTransaction(PersonalAccount from, BusinessAccount to, int amount); + <> InstantTransaction transfer_InstantTransaction(BusinessAccount from, PersonalAccount to, int amount); + <> InstantTransaction transfer_InstantTransaction(BusinessAccount from, BusinessAccount to, int amount); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIConc.cd new file mode 100644 index 00000000..18756dee --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIConc.cd @@ -0,0 +1,5 @@ +classdiagram ParameterTypeMIConc { + + <> class PersonalAccount; + <> class BusinessAccount; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIOneExistsConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIOneExistsConc.cd new file mode 100644 index 00000000..44462a71 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIOneExistsConc.cd @@ -0,0 +1,9 @@ +classdiagram ParameterTypeMIOneExistsConc { + + <> class PersonalAccount; + <> class BusinessAccount; + + class Bank { + void createAccount(PersonalAccount account); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIOneExistsOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIOneExistsOut.cd new file mode 100644 index 00000000..2d7133ce --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIOneExistsOut.cd @@ -0,0 +1,20 @@ +classdiagram ParameterTypeMIOneExistsConc { + + <> class PersonalAccount; + <> class BusinessAccount; + + class Transaction; + + class Bank { + void createAccount(PersonalAccount account); + // NO second createAccount method, for BusinessAccount because we already have one incarnation + // that satisfies the conformance check + // if we want the tool to complete all combinations: use "forEach" in reference model + // --- + // for 'transfer' all possible combinations are completed as there was not a single incarnation + <> Transaction transfer(PersonalAccount from, PersonalAccount to, int amount); + <> Transaction transfer(PersonalAccount from, BusinessAccount to, int amount); + <> Transaction transfer(BusinessAccount from, PersonalAccount to, int amount); + <> Transaction transfer(BusinessAccount from, BusinessAccount to, int amount); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIOut.cd new file mode 100644 index 00000000..df3a3e5a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ParameterTypeMIOut.cd @@ -0,0 +1,16 @@ +classdiagram ParameterTypeMIConc { + + <> class PersonalAccount; + <> class BusinessAccount; + + class Transaction; + + class Bank { + <> void createPersonalAccount(PersonalAccount personalAccount); + <> void createBusinessAccount(BusinessAccount businessAccount); + <> Transaction transfer(PersonalAccount from, PersonalAccount to, int amount); + <> Transaction transfer(PersonalAccount from, BusinessAccount to, int amount); + <> Transaction transfer(BusinessAccount from, PersonalAccount to, int amount); + <> Transaction transfer(BusinessAccount from, BusinessAccount to, int amount); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/Reference.cd new file mode 100644 index 00000000..116b5429 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/Reference.cd @@ -0,0 +1,10 @@ +classdiagram Reference { + class Account; + + class Transaction; + + class Bank { + void createAccount(Account account); + Transaction transfer(Account from, Account to, int amount); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIConc.cd new file mode 100644 index 00000000..438e69c1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIConc.cd @@ -0,0 +1,5 @@ +classdiagram ReturnTypeMIConc { + + <> class NormalTransaction; + <> class InstantTransaction; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIOneExistsConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIOneExistsConc.cd new file mode 100644 index 00000000..997b247c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIOneExistsConc.cd @@ -0,0 +1,11 @@ +classdiagram ReturnTypeMIOneExistsConc { + + <> class NormalTransaction; + <> class InstantTransaction; + + class Account; + + class Bank { + NormalTransaction transfer(Account from, Account to, int amount); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIOneExistsOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIOneExistsOut.cd new file mode 100644 index 00000000..d49ec11c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIOneExistsOut.cd @@ -0,0 +1,15 @@ +classdiagram ReturnTypeMIOneExistsConc { + + <> class NormalTransaction; + <> class InstantTransaction; + + class Account; + + class Bank { + void createAccount(Account account); + NormalTransaction transfer(Account from, Account to, int amount); + // NO second 'transfer' method, for InstantTransaction because we already have one incarnation + // that satisfies the conformance check + // if we want the tool to complete all combinations: use "forEach" in reference model + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIOut.cd new file mode 100644 index 00000000..557fde3b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/ReturnTypeMIOut.cd @@ -0,0 +1,13 @@ +classdiagram ReturnTypeMIConc { + + <> class NormalTransaction; + <> class InstantTransaction; + + class Account; + + class Bank { + void createAccount(Account account); + <> NormalTransaction transfer_NormalTransaction(Account from, Account to, int amount); + <> InstantTransaction transfer_InstantTransaction(Account from, Account to, int amount); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/adapter/Bank.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/adapter/Bank.java new file mode 100644 index 00000000..ea6e428a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/adapter/Bank.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Bank"}, template = "${}") +public class Bank { + @Adapt(ref = {"Bank.createAccount"}, template = "${}") + public void createAccount(Account account) { + } + + @Adapt(ref = {"Bank.transfer"}, template = "${}") + public Transaction transfer(Account from, Account to, int amount) { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/adapter/Transaction.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/adapter/Transaction.java new file mode 100644 index 00000000..1972a775 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/adapter/Transaction.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Transaction"}, template = "${}") +public class Transaction { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/Bank.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/Bank.java new file mode 100644 index 00000000..a83b80cd --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/Bank.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; + +public class Bank { + public NormalTransaction transfer(Account from, Account to, int amount) { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/BusinessAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/BusinessAccount.java new file mode 100644 index 00000000..cb73b734 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/BusinessAccount.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; + +public class BusinessAccount { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/InstantTransaction.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/InstantTransaction.java new file mode 100644 index 00000000..9f33d75b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/InstantTransaction.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; + +public class InstantTransaction { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/NormalTransaction.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/NormalTransaction.java new file mode 100644 index 00000000..f84c5991 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/NormalTransaction.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; + +public class NormalTransaction { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ParameterTypeMIOneExists/Bank.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ParameterTypeMIOneExists/Bank.java new file mode 100644 index 00000000..f7db939e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ParameterTypeMIOneExists/Bank.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.parametertypemioneexists; + +public class Bank { + public void createAccount(PersonalAccount account) { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/PersonalAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/PersonalAccount.java new file mode 100644 index 00000000..d7a188c7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/PersonalAccount.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation; + +public class PersonalAccount { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/Account.java new file mode 100644 index 00000000..bdd9735d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/Account.java @@ -0,0 +1,3 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.returntypemioneexists; + +public class Account {} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/Bank.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/Bank.java new file mode 100644 index 00000000..616ad003 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/Bank.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.returntypemioneexists; + +public class Bank { + public NormalTransaction transfer(Account from, Account to, int amount) { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/InstantTransaction.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/InstantTransaction.java new file mode 100644 index 00000000..d5444c2f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/InstantTransaction.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.returntypemioneexists; + +public class InstantTransaction { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/NormalTransaction.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/NormalTransaction.java new file mode 100644 index 00000000..fb25c289 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/multiIncarnation/concrete/ReturnTypeMIOneExists/NormalTransaction.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.methods.multiincarnation.concrete.returntypemioneexists; + +public class NormalTransaction { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedIncarnatedConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedIncarnatedConc.cd new file mode 100644 index 00000000..3fe6e40d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedIncarnatedConc.cd @@ -0,0 +1,8 @@ +import java.lang.String; + +classdiagram ParameterTypeUnderspecifiedIncarnatedConc { + + <> class MyOperator { + <> void foo(String param); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedIncarnatedOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedIncarnatedOut.cd new file mode 100644 index 00000000..c1867e35 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedIncarnatedOut.cd @@ -0,0 +1,9 @@ +import java.lang.String; + +classdiagram ParameterTypeUnderspecifiedIncarnatedConc { + + <> class MyOperator { + // nothing changed. we just make sure the tool can process the input and does not add anything + <> void foo(String param); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedNoIncConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedNoIncConc.cd new file mode 100644 index 00000000..00410f44 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedNoIncConc.cd @@ -0,0 +1,8 @@ +classdiagram ParameterTypeUnderspecifiedRef { + + <> class MyOperator { + // NOTE: we have no incarnation of "operation(any)" + // -> leads to error because a parameter is underspecified + void foo(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedRef.cd new file mode 100644 index 00000000..aec36122 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ParameterTypeUnderspecifiedRef.cd @@ -0,0 +1,6 @@ +classdiagram ParameterTypeUnderspecifiedRef { + + class Operator { + void operation(any param); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedIncarnatedConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedIncarnatedConc.cd new file mode 100644 index 00000000..a60a25bf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedIncarnatedConc.cd @@ -0,0 +1,6 @@ +classdiagram ReturnTypeUnderspecifiedIncarnatedConc { + + <> class MyOperator { + <> void foo(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedIncarnatedOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedIncarnatedOut.cd new file mode 100644 index 00000000..5dd5d438 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedIncarnatedOut.cd @@ -0,0 +1,7 @@ +classdiagram ReturnTypeUnderspecifiedIncarnatedConc { + + <> class MyOperator { + // nothing changed. we just make sure the tool can process the input and does not add anything + <> void foo(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedNoIncConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedNoIncConc.cd new file mode 100644 index 00000000..8673bb5c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedNoIncConc.cd @@ -0,0 +1,8 @@ +classdiagram ReturnTypeUnderspecifiedRef { + + <> class MyOperator { + // NOTE: we have no incarnation of "operation()" + // -> leads to error because the return type is underspecified + void foo(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedRef.cd new file mode 100644 index 00000000..fabe4433 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/ReturnTypeUnderspecifiedRef.cd @@ -0,0 +1,6 @@ +classdiagram ReturnTypeUnderspecifiedRef { + + class Operator { + any operation(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/adapter/ParameterTypeUnderspecifiedIncarnated/Operator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/adapter/ParameterTypeUnderspecifiedIncarnated/Operator.java new file mode 100644 index 00000000..0b3d52d2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/adapter/ParameterTypeUnderspecifiedIncarnated/Operator.java @@ -0,0 +1,11 @@ +package de.monticore.codeAdaption.cdconcretization.methods.underspecified.adapter.parametertypeunderspecifiedincarnated; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Operator"}, template = "${}") +public class Operator { + @Adapt(ref = {"Operator.operation"}, template = "${}") + public void operation(Object param) { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/adapter/ReturnTypeUnderspecifiedIncarnated/Operator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/adapter/ReturnTypeUnderspecifiedIncarnated/Operator.java new file mode 100644 index 00000000..1f8f0bb3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/adapter/ReturnTypeUnderspecifiedIncarnated/Operator.java @@ -0,0 +1,12 @@ +package de.monticore.codeAdaption.cdconcretization.methods.underspecified.adapter.returntypeunderspecifiedincarnated; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Operator"}, template = "${}") +public class Operator { + @Adapt(ref = {"Operator.operation"}, template = "${}") + public Object operation() { + return null; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/concrete/MyOperator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/concrete/MyOperator.java new file mode 100644 index 00000000..48dbb93b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/methods/underspecified/concrete/MyOperator.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.methods.underspecified; + +public class MyOperator { + public void foo() { + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/AttributeTypeMIConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/AttributeTypeMIConc.cd new file mode 100644 index 00000000..44a59579 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/AttributeTypeMIConc.cd @@ -0,0 +1,6 @@ +classdiagram AttributeTypeMIConc { + + <> class Salery; + + <> class CompanyIdentifier; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/AttributeTypeMIOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/AttributeTypeMIOut.cd new file mode 100644 index 00000000..9c8366fa --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/AttributeTypeMIOut.cd @@ -0,0 +1,11 @@ +classdiagram AttributeTypeMIConc { + + <> class Salery; + + <> class CompanyIdentifier; + + class Employee { + <> CompanyIdentifier value_CompanyIdentifier; + <> Salery value_Salery; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/AttributeTypeMIRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/AttributeTypeMIRef.cd new file mode 100644 index 00000000..f17066a7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/AttributeTypeMIRef.cd @@ -0,0 +1,8 @@ +classdiagram AttributeTypeMIRef { + + class SomeValueType; + + class Employee { + SomeValueType value; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIConc.cd new file mode 100644 index 00000000..0f1756ec --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIConc.cd @@ -0,0 +1,15 @@ +classdiagram BothAssocSidesMIConc { + + <> class SuperTeacher1 { + } + <> class SuperTeacher2 { + } + <> class Teacher1 { + } + <> class Teacher2 { + } + <> class Department1 { + } + <> class Department2 { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMINameAdaptationOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMINameAdaptationOut.cd new file mode 100644 index 00000000..aadd20ad --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMINameAdaptationOut.cd @@ -0,0 +1,15 @@ +classdiagram BothAssocSidesMIConc { + <> class SuperTeacher1; + <> class SuperTeacher2; + + <> class Teacher1 extends SuperTeacher2, SuperTeacher1; + <> class Teacher2 extends SuperTeacher2, SuperTeacher1; + + <> class Department1; + <> class Department2; + + association Teacher1 (hasTeacher1) -- (teachesIn_Department1) Department1; + association Teacher1 (hasTeacher1) -- (teachesIn_Department2) Department2; + association Teacher2 (hasTeacher2) -- (teachesIn_Department1) Department1; + association Teacher2 (hasTeacher2) -- (teachesIn_Department2) Department2; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIOneAssocExistsConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIOneAssocExistsConc.cd new file mode 100644 index 00000000..98af766d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIOneAssocExistsConc.cd @@ -0,0 +1,18 @@ +classdiagram BothAssocSidesMIConc { + + <> class SuperTeacher1 { + } + <> class SuperTeacher2 { + } + <> class Teacher1 { + } + <> class Teacher2 { + } + <> class Department1 { + } + <> class Department2 { + } + + association Teacher1 (hasTeacher) -- (teachesIn) Department1; + association Teacher2 (hasTeacher) -- (teachesIn) Department2; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIOneAssocExistsOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIOneAssocExistsOut.cd new file mode 100644 index 00000000..95f0521f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIOneAssocExistsOut.cd @@ -0,0 +1,25 @@ +classdiagram BothAssocSidesMIConc { + <>class SuperTeacher1 { + + } + <>class SuperTeacher2 { + + } + <>class Teacher1 extends SuperTeacher2,SuperTeacher1 { + + } + <>class Teacher2 extends SuperTeacher2,SuperTeacher1 { + + } + <>class Department1 { + + } + <>class Department2 { + + } + + association Teacher1(hasTeacher1)--(teachesIn)Department1; + association Teacher2(hasTeacher2)--(teachesIn)Department2; + // no more associations are added here because each type incarnation already has one association +} + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIOut.cd new file mode 100644 index 00000000..aadd20ad --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIOut.cd @@ -0,0 +1,15 @@ +classdiagram BothAssocSidesMIConc { + <> class SuperTeacher1; + <> class SuperTeacher2; + + <> class Teacher1 extends SuperTeacher2, SuperTeacher1; + <> class Teacher2 extends SuperTeacher2, SuperTeacher1; + + <> class Department1; + <> class Department2; + + association Teacher1 (hasTeacher1) -- (teachesIn_Department1) Department1; + association Teacher1 (hasTeacher1) -- (teachesIn_Department2) Department2; + association Teacher2 (hasTeacher2) -- (teachesIn_Department1) Department1; + association Teacher2 (hasTeacher2) -- (teachesIn_Department2) Department2; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIRef.cd new file mode 100644 index 00000000..40bd1aeb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/BothAssocSidesMIRef.cd @@ -0,0 +1,10 @@ +classdiagram BothAssocSidesMIRef { + + class SuperTeacher { + } + class Teacher extends SuperTeacher { + } + class Department { + } + association Teacher (hasTeacher) -- (teachesIn) Department; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/ClassMIConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/ClassMIConc.cd new file mode 100644 index 00000000..6262d296 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/ClassMIConc.cd @@ -0,0 +1,8 @@ +classdiagram ClassMIConc { + <> class Operations { + int supervisorID; + } + <> class Administration { + int managerID; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/ClassMIOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/ClassMIOut.cd new file mode 100644 index 00000000..90d23212 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/ClassMIOut.cd @@ -0,0 +1,11 @@ +classdiagram ClassMIConc { + <> class Operations { + int supervisorID; + int deptID; + } + + <> class Administration { + int managerID; + int deptID; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/ClassMIRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/ClassMIRef.cd new file mode 100644 index 00000000..b0ba1e67 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/ClassMIRef.cd @@ -0,0 +1,5 @@ +classdiagram ClassMIRef { + class Department { + int deptID; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/InterfaceMIConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/InterfaceMIConc.cd new file mode 100644 index 00000000..9d55fe13 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/InterfaceMIConc.cd @@ -0,0 +1,6 @@ +classdiagram InterfaceMIConc { + + <> interface IEmployee1; + + <> interface IEmployee2; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/InterfaceMIOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/InterfaceMIOut.cd new file mode 100644 index 00000000..d019f698 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/InterfaceMIOut.cd @@ -0,0 +1,9 @@ +classdiagram InterfaceMIConc { + + <> interface IEmployee1; + + <> interface IEmployee2; + + class Employee implements IEmployee1, IEmployee2; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/InterfaceMIRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/InterfaceMIRef.cd new file mode 100644 index 00000000..4aaab1c0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/InterfaceMIRef.cd @@ -0,0 +1,6 @@ +classdiagram InterfaceMIRef { + + interface IEmployee; + + class Employee implements IEmployee; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/UnequalCardCon.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/UnequalCardCon.cd new file mode 100644 index 00000000..b6cd7839 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/UnequalCardCon.cd @@ -0,0 +1,14 @@ +classdiagram UnequalCardCon { + class Company { + } + + <> class Worker { + } + + <> class Manager { + } + + association Company -- Manager [1]; + association Company -- Worker [0..1]; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/UnequalCardRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/UnequalCardRef.cd new file mode 100644 index 00000000..686d34af --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/UnequalCardRef.cd @@ -0,0 +1,9 @@ +classdiagram RefTest { + class Company { + } + + class Employee { + } + association Company -- Employee [1..*]; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/AttributeTypeMI/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/AttributeTypeMI/Employee.java new file mode 100644 index 00000000..e9ef570c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/AttributeTypeMI/Employee.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.multipleincarnation.adapter.attributetypemi; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Employee"}, template = "${}") +public class Employee { + @Adapt(ref = {"Employee.value"}, template = "${}") + private SomeValueType value; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/AttributeTypeMI/SomeValueType.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/AttributeTypeMI/SomeValueType.java new file mode 100644 index 00000000..1cc918f6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/AttributeTypeMI/SomeValueType.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.multipleincarnation.adapter.attributetypemi; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"SomeValueType"}, template = "${}") +public class SomeValueType { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/BothAssocSidesMI/SuperTeacher.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/BothAssocSidesMI/SuperTeacher.java new file mode 100644 index 00000000..24bacff5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/BothAssocSidesMI/SuperTeacher.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.multipleincarnation.adapter.bothassocsidesmi; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"SuperTeacher"}, template = "${}") +public class SuperTeacher { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/BothAssocSidesMI/Teacher.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/BothAssocSidesMI/Teacher.java new file mode 100644 index 00000000..7cb94433 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/BothAssocSidesMI/Teacher.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.multipleincarnation.adapter.bothassocsidesmi; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Teacher"}, template = "${}") +public class Teacher extends SuperTeacher { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/ClassMI/Department.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/ClassMI/Department.java new file mode 100644 index 00000000..9acb67d6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/ClassMI/Department.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.cdconcretization.multipleincarnation.adapter.classmi; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Department"}, template = "${}") +public class Department { + @Adapt(ref = {"Department.deptID"}, template = "${}") + private int deptID; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/InterfaceMI/Employee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/InterfaceMI/Employee.java new file mode 100644 index 00000000..48d96e12 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/InterfaceMI/Employee.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.multipleincarnation.adapter.interfacemi; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Employee"}, template = "${}") +public class Employee { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/InterfaceMI/IEmployee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/InterfaceMI/IEmployee.java new file mode 100644 index 00000000..00e39b48 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/adapter/InterfaceMI/IEmployee.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.multipleincarnation.adapter.interfacemi; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"IEmployee"}, template = "${}") +public interface IEmployee { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/concrete/IEmployee1.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/concrete/IEmployee1.java new file mode 100644 index 00000000..91a933f6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/concrete/IEmployee1.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.multipleincarnation; + +public interface IEmployee1 { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/concrete/IEmployee2.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/concrete/IEmployee2.java new file mode 100644 index 00000000..9b4af290 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/multipleIncarnation/concrete/IEmployee2.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.multipleincarnation; + +public interface IEmployee2 { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/EnumMemberMissingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/EnumMemberMissingConc.cd new file mode 100644 index 00000000..5ba6d713 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/EnumMemberMissingConc.cd @@ -0,0 +1,4 @@ +classdiagram EnumMemberMissingConc { + enum Colour{RED,YELLOW,BLUE,PURPLE; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/EnumMemberMissingOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/EnumMemberMissingOut.cd new file mode 100644 index 00000000..f6ebc8dc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/EnumMemberMissingOut.cd @@ -0,0 +1,5 @@ +classdiagram EnumMemberMissingConc { + enum Colour { + RED,GREEN,YELLOW,BLUE,PURPLE; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/EnumMemberMissingRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/EnumMemberMissingRef.cd new file mode 100644 index 00000000..1146df58 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/EnumMemberMissingRef.cd @@ -0,0 +1,4 @@ +classdiagram EnumMemberMissingRef { + enum Colour{RED,GREEN,BLUE; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/adapter/EnumMemberMissing/Colour.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/adapter/EnumMemberMissing/Colour.java new file mode 100644 index 00000000..1bfc9e4c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/adapter/EnumMemberMissing/Colour.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.types.enums.adapter.enummembermissing; + +public enum Colour { + RED, + GREEN, + BLUE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/concrete/Colour.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/concrete/Colour.java new file mode 100644 index 00000000..0833199c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/enums/concrete/Colour.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.cdconcretization.types.enums; + +public enum Colour { + RED, + YELLOW, + BLUE, + PURPLE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeConc.cd new file mode 100644 index 00000000..8ae1ffe0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeConc.cd @@ -0,0 +1,7 @@ +classdiagram ForEachTypeConc { + <> class Employee; + + <> class Department; + + <> class Company; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeForEachAttributeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeForEachAttributeConc.cd new file mode 100644 index 00000000..80367cf2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeForEachAttributeConc.cd @@ -0,0 +1,15 @@ +import java.lang.String; + +classdiagram ForEachTypeForEachAttributeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + <> String managerName; + <> int depId; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeForEachAttributeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeForEachAttributeOut.cd new file mode 100644 index 00000000..d1cf4a5f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeForEachAttributeOut.cd @@ -0,0 +1,29 @@ +import java.lang.String; + +classdiagram ForEachTypeForEachAttributeConc { + <> class Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> class Department { + <> String managerName; + <> int depId; + } + + <> + class Builder_Employee { + <> String firstName; + <> String lastName; + <> int number; + <> int salary; + } + + <> + class Builder_Department { + <> String managerName; + <> int depId; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeForEachAttributeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeForEachAttributeRef.cd new file mode 100644 index 00000000..ad1cf61a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeForEachAttributeRef.cd @@ -0,0 +1,12 @@ + +classdiagram ForEachTypeForEachAttributeRef { + class DataClass { + any attribute; + } + + <> class Builder { + // Incarnations will have the same name as the referenced attribute incarnations by convention + // because the referenced attribute has the same name as the annotated attribute! + <> any attribute; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceConc.cd new file mode 100644 index 00000000..c4d7012c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceConc.cd @@ -0,0 +1,7 @@ +classdiagram ForEachTypeInfixReplaceConc { + <> class Employee; + + <> class Department; + + <> class Company; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceDisabledOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceDisabledOut.cd new file mode 100644 index 00000000..087c344f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceDisabledOut.cd @@ -0,0 +1,19 @@ +classdiagram ForEachTypeInfixReplaceConc { + <> class Employee; + + <> class Department; + + <> class Company; + + <> class DataClassBuilder_Employee { + + } + + <> class DataClassBuilder_Department { + + } + + <> class DataClassBuilder_Company{ + + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceOut.cd new file mode 100644 index 00000000..3766efa2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceOut.cd @@ -0,0 +1,19 @@ +classdiagram ForEachTypeInfixReplaceConc { + <> class Employee; + + <> class Department; + + <> class Company; + + <> class EmployeeBuilder { + + } + + <> class DepartmentBuilder { + + } + + <> class CompanyBuilder { + + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceRef.cd new file mode 100644 index 00000000..e8f9de57 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeInfixReplaceRef.cd @@ -0,0 +1,11 @@ +classdiagram ForEachTypeRef { + class DataClass { + + } + + // DataClass is an infix of 'DataClassBuilder'. Therefore, 'DataClass' is replaced with the + // incarnation name of 'DataClass' in the output + <> class DataClassBuilder { + + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeNoTargetIncConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeNoTargetIncConc.cd new file mode 100644 index 00000000..a591fd91 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeNoTargetIncConc.cd @@ -0,0 +1,3 @@ +classdiagram ForEachTypeNoTargetIncConc { + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeNoTargetIncOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeNoTargetIncOut.cd new file mode 100644 index 00000000..1362e902 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeNoTargetIncOut.cd @@ -0,0 +1,7 @@ +classdiagram ForEachTypeNoTargetIncConc { + class DataClass; + + <> class Builder { + + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeOut.cd new file mode 100644 index 00000000..3523c9e2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeOut.cd @@ -0,0 +1,19 @@ +classdiagram ForEachTypeConc { + <> class Employee; + + <> class Department; + + <> class Company; + + <> class Builder_Employee { + + } + + <> class Builder_Department { + + } + + <> class Builder_Company { + + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeRef.cd new file mode 100644 index 00000000..3ecc5c4c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/ForEachTypeRef.cd @@ -0,0 +1,9 @@ +classdiagram ForEachTypeRef { + class DataClass { + + } + + <> class Builder { + + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/adapter/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/adapter/Builder.java new file mode 100644 index 00000000..9a9656f0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/adapter/Builder.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.types.foreach; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}") +public class Builder { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/adapter/DataClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/adapter/DataClass.java new file mode 100644 index 00000000..efaec237 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/forEach/adapter/DataClass.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.types.foreach; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"DataClass"}, template = "${}") +public class DataClass { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingConc.cd new file mode 100644 index 00000000..3da6126a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingConc.cd @@ -0,0 +1,12 @@ +classdiagram TypeMissingConc { + + class Course { + } + + enum CourseType { + LECTURE, + SEMINAR, + TUTORIAL; + + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingOut.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingOut.cd new file mode 100644 index 00000000..38c788ae --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingOut.cd @@ -0,0 +1,22 @@ +classdiagram TypeMissingConc { + class Course implements Teachable; + + interface Teachable; + + enum CourseType { + /* + * NOTE: The enum value position from the reference CD is preserved! + * This is important as reference code could access the values by index. + */ + LECTURE, + EXERCICE, + SEMINAR, + TUTORIAL; + } + + enum CourseStatus { + ACTIVE, + COMPLETED, + CANCELLED; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingRef.cd new file mode 100644 index 00000000..5322c241 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/TypeMissingRef.cd @@ -0,0 +1,18 @@ +classdiagram TypeMissingRef { + interface Teachable { + } + + class Course implements Teachable { + } + + enum CourseStatus { + ACTIVE, + COMPLETED, + CANCELLED; + } + + enum CourseType { + LECTURE, + EXERCICE; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/Course.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/Course.java new file mode 100644 index 00000000..49da829d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/Course.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.types.valid.adapter.typemissing; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Course"}, template = "${}") +public class Course { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/CourseStatus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/CourseStatus.java new file mode 100644 index 00000000..f28b5800 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/CourseStatus.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.types.valid.adapter.typemissing; + +public enum CourseStatus { + ACTIVE, + COMPLETED, + CANCELLED; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/CourseType.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/CourseType.java new file mode 100644 index 00000000..d3484986 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/CourseType.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.cdconcretization.types.valid.adapter.typemissing; + +public enum CourseType { + LECTURE, + EXERCICE; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/Teachable.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/Teachable.java new file mode 100644 index 00000000..4aef778d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/adapter/TypeMissing/Teachable.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.types.valid.adapter.typemissing; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Teachable"}, template = "${}") +public interface Teachable { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/concrete/Course.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/concrete/Course.java new file mode 100644 index 00000000..32be6f1c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/concrete/Course.java @@ -0,0 +1,4 @@ +package de.monticore.codeAdaption.cdconcretization.types.valid; + +public class Course { +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/concrete/CourseType.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/concrete/CourseType.java new file mode 100644 index 00000000..1cdc4363 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/types/valid/concrete/CourseType.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.cdconcretization.types.valid; + +public enum CourseType { + LECTURE, + SEMINAR, + TUTORIAL; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/util/MethodSignatureStrings.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/util/MethodSignatureStrings.cd new file mode 100644 index 00000000..54ce82ee --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/cdconcretization/util/MethodSignatureStrings.cd @@ -0,0 +1,17 @@ +import java.lang.String; + +classdiagram MethodSignatureStrings { + class A { + // m1 must be resolved with full signature as the name itself is not unique + void m1(); + void m1(int i); + void m1(String s); + void m1(int i, String s); + void m1(int i, String s, double d); + void m1(int i, String s, double d, boolean b); + + // m2 and m3 can be resolved with the name only, no matter if they have parameters or not + int m2(); + String m3(int i, String s); + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AmbiguousOverloadConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AmbiguousOverloadConc.cd new file mode 100644 index 00000000..815a63d2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AmbiguousOverloadConc.cd @@ -0,0 +1,5 @@ +classdiagram AmbiguousOverloadConc { + <> class Service { + <> void syncConcrete(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AmbiguousOverloadRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AmbiguousOverloadRef.cd new file mode 100644 index 00000000..cee66525 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AmbiguousOverloadRef.cd @@ -0,0 +1,6 @@ +classdiagram AmbiguousOverloadRef { + class Service { + void sync(); + void sync(int value); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AnyConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AnyConc.cd new file mode 100644 index 00000000..a4009697 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AnyConc.cd @@ -0,0 +1,3 @@ +classdiagram AnyConc { + <> class Employee; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AnyRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AnyRef.cd new file mode 100644 index 00000000..ddd0f98c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AnyRef.cd @@ -0,0 +1,5 @@ +classdiagram AnyRef { + class DataClass { + any attribute; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationAmbiguousDirectionConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationAmbiguousDirectionConc.cd new file mode 100644 index 00000000..b4a26e66 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationAmbiguousDirectionConc.cd @@ -0,0 +1,6 @@ +classdiagram AssociationAmbiguousDirectionConc { + <> class LeftNode; + <> class RightNode; + + association LeftNode -- RightNode; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationAmbiguousDirectionRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationAmbiguousDirectionRef.cd new file mode 100644 index 00000000..f8c8c409 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationAmbiguousDirectionRef.cd @@ -0,0 +1,5 @@ +classdiagram AssociationAmbiguousDirectionRef { + class Node; + + association Node -- Node; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationCardinalityConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationCardinalityConc.cd new file mode 100644 index 00000000..3234b66b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationCardinalityConc.cd @@ -0,0 +1,6 @@ +classdiagram AssociationCardinalityConc { + <> class Company; + <> class Employee; + + association Company (company) -- (employees) Employee [1]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationCardinalityRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationCardinalityRef.cd new file mode 100644 index 00000000..b7edf231 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationCardinalityRef.cd @@ -0,0 +1,6 @@ +classdiagram AssociationCardinalityRef { + class Company; + class Employee; + + association Company (company) -- (employees) Employee [1..*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationRoleConflictConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationRoleConflictConc.cd new file mode 100644 index 00000000..210eee7c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationRoleConflictConc.cd @@ -0,0 +1,7 @@ +classdiagram AssociationRoleConflictConc { + <> class WiMi; + <> class StudentData; + class Lecture; + + association WiMi -> (observes) Lecture; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationRoleConflictRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationRoleConflictRef.cd new file mode 100644 index 00000000..f732d427 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/AssociationRoleConflictRef.cd @@ -0,0 +1,6 @@ +classdiagram AssociationRoleConflictRef { + class Observer; + class Observable; + + association Observer -> (observes) Observable; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/EnumOrderConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/EnumOrderConc.cd new file mode 100644 index 00000000..4281281f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/EnumOrderConc.cd @@ -0,0 +1,6 @@ +classdiagram EnumOrderConc { + <> enum Status { + DONE, + NEW; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/EnumOrderRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/EnumOrderRef.cd new file mode 100644 index 00000000..c69676cf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/EnumOrderRef.cd @@ -0,0 +1,6 @@ +classdiagram EnumOrderRef { + enum Status { + NEW, + DONE; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/FieldConflictConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/FieldConflictConc.cd new file mode 100644 index 00000000..064ee3fa --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/FieldConflictConc.cd @@ -0,0 +1,10 @@ +import java.lang.String; +classdiagram FieldConflictConc { + class Base { + int id; + } + + <> class Employee extends Base { + String id; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/FieldConflictRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/FieldConflictRef.cd new file mode 100644 index 00000000..78831b0c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/FieldConflictRef.cd @@ -0,0 +1,3 @@ +classdiagram FieldConflictRef { + class Person; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachAttributeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachAttributeConc.cd new file mode 100644 index 00000000..38aa59b2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachAttributeConc.cd @@ -0,0 +1,7 @@ +import java.lang.String; +classdiagram ForEachAttributeConc { + <> class Employee { + <> String firstName; + <> int age; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachAttributeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachAttributeRef.cd new file mode 100644 index 00000000..98fd5e5a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachAttributeRef.cd @@ -0,0 +1,9 @@ +classdiagram ForEachAttributeRef { + class DataClass { + any attribute; + } + + class Builder { + <> any attribute; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodConc.cd new file mode 100644 index 00000000..e503f05a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodConc.cd @@ -0,0 +1,9 @@ +import java.lang.String; +classdiagram ForEachMethodConc { + <> class Employee { + <> String firstName; + <> int age; + String getFirstName(); + int getAge(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodExactConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodExactConc.cd new file mode 100644 index 00000000..31331a5b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodExactConc.cd @@ -0,0 +1,10 @@ +import java.lang.String; +classdiagram ForEachMethodExactConc { + <> class Employee { + <> String copyEmployee(); + } + + <> class Department { + <> int copyDepartment(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodExactRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodExactRef.cd new file mode 100644 index 00000000..180f2eb4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodExactRef.cd @@ -0,0 +1,9 @@ +classdiagram ForEachMethodExactRef { + class DataClass { + any copy(); + } + + class Builder { + <> any copy(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodRef.cd new file mode 100644 index 00000000..f68af9f5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodRef.cd @@ -0,0 +1,6 @@ +classdiagram ForEachMethodRef { + class DataClass { + any attribute; + <> any getAttribute(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodSubstringConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodSubstringConc.cd new file mode 100644 index 00000000..699c6249 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodSubstringConc.cd @@ -0,0 +1,9 @@ +import java.lang.String; +classdiagram ForEachMethodSubstringConc { + <> class Employee { + <> String firstName; + <> int age; + String getFirstNameable(); + int getAgeable(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodSubstringRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodSubstringRef.cd new file mode 100644 index 00000000..c2d0c4e0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMethodSubstringRef.cd @@ -0,0 +1,6 @@ +classdiagram ForEachMethodSubstringRef { + class DataClass { + any attribute; + <> any getAttributable(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMissingConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMissingConc.cd new file mode 100644 index 00000000..443867c0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMissingConc.cd @@ -0,0 +1,6 @@ +import java.lang.String; +classdiagram ForEachMissingConc { + <> class Employee { + <> String firstName; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMissingRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMissingRef.cd new file mode 100644 index 00000000..ea85545b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachMissingRef.cd @@ -0,0 +1,9 @@ +classdiagram ForEachMissingRef { + class DataClass { + any attribute; + } + + class Builder { + <> any attribute; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachTypeConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachTypeConc.cd new file mode 100644 index 00000000..d95e9cea --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachTypeConc.cd @@ -0,0 +1,4 @@ +classdiagram ForEachTypeConc { + <> class Employee; + <> class Department; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachTypeRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachTypeRef.cd new file mode 100644 index 00000000..8371334d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ForEachTypeRef.cd @@ -0,0 +1,4 @@ +classdiagram ForEachTypeRef { + class DataClass; + <> class DataClassBuilder; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/MethodConflictConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/MethodConflictConc.cd new file mode 100644 index 00000000..5121a41a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/MethodConflictConc.cd @@ -0,0 +1,7 @@ +import java.lang.String; +classdiagram MethodConflictConc { + <> class Service { + int value(); + String value(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/MethodConflictRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/MethodConflictRef.cd new file mode 100644 index 00000000..2fc0e3ad --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/MethodConflictRef.cd @@ -0,0 +1,3 @@ +classdiagram MethodConflictRef { + class Service; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/TypeKindConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/TypeKindConc.cd new file mode 100644 index 00000000..9efc4226 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/TypeKindConc.cd @@ -0,0 +1,3 @@ +classdiagram TypeKindConc { + <> interface Service; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/TypeKindRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/TypeKindRef.cd new file mode 100644 index 00000000..3cbce00a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/TypeKindRef.cd @@ -0,0 +1,3 @@ +classdiagram TypeKindRef { + class Service; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ValidManualConc.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ValidManualConc.cd new file mode 100644 index 00000000..ee79b820 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ValidManualConc.cd @@ -0,0 +1,6 @@ +classdiagram ValidManualConc { + <> class BankAccount { + <> int amount; + <> int readAmount(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ValidManualRef.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ValidManualRef.cd new file mode 100644 index 00000000..054c09fd --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/ValidManualRef.cd @@ -0,0 +1,6 @@ +classdiagram ValidManualRef { + class Account { + int balance; + int getBalance(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/adapter/Account.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/adapter/Account.java new file mode 100644 index 00000000..d045a9f7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/adapter/Account.java @@ -0,0 +1,12 @@ +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(template = "Account", value = {"Account"}) +class Account { + @Adapt(template = "balance", value = {"balance"}) + private int balance; + + @Adapt(template = "getBalance", value = {"getBalance"}) + int getBalance() { + return balance; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/concrete/BankAccount.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/concrete/BankAccount.java new file mode 100644 index 00000000..8b8ddab0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/conflicts/concrete/BankAccount.java @@ -0,0 +1,3 @@ +class BankAccount { + private int amount; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Concrete.cd index 5133fbcf..31a59f94 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Concrete.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Concrete.cd @@ -1,5 +1,5 @@ -package de.monticore.codeAdaption.evaluation; import java.lang.String; +import java.util.Date; classdiagram Concrete { diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Reference.cd index 22969782..cda8aaca 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Reference.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Reference.cd @@ -1,5 +1,5 @@ -package de.monticore.codeAdaption.evaluation; import java.lang.String; +import java.util.Date; classdiagram Reference { diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/Concrete.cd new file mode 100644 index 00000000..0d538109 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/Concrete.cd @@ -0,0 +1,6 @@ +classdiagram Concrete { + <> class Sprint; + <> class Ticket; + + association [1] Sprint (sprint) <-> (tickets) Ticket [1]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/Reference.cd new file mode 100644 index 00000000..76f309b0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/Reference.cd @@ -0,0 +1,6 @@ +classdiagram Reference { + class Project; + class Task; + + association [1] Project (project) <-> (tasks) Task [1]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/adapter/Project.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/adapter/Project.java new file mode 100644 index 00000000..9667c826 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/adapter/Project.java @@ -0,0 +1,12 @@ +package Concrete; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Project"}, template = "${}") +public class Project extends ProjectTOP { + + @Adapt(ref = {"Task"}, template = "replace${}") + public void replaceTask(Task replacement) { + this.tasks = replacement; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/adapter/Task.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/adapter/Task.java new file mode 100644 index 00000000..2cc0fcf9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_bidirectional_role_write/adapter/Task.java @@ -0,0 +1,12 @@ +package Concrete; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Task"}, template = "${}") +public class Task extends TaskTOP { + + @Adapt(ref = {"Project"}, template = "moveTo${}") + public void moveToProject(Project replacement) { + this.project = replacement; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_role_usage_mi/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_role_usage_mi/Concrete.cd new file mode 100644 index 00000000..0052bc09 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_role_usage_mi/Concrete.cd @@ -0,0 +1,8 @@ +classdiagram Concrete { + <> class Teacher; + <> class MathDept; + <> class ScienceDept; + + association Teacher -> (mathDepts) MathDept [*]; + association Teacher -> (scienceDepts) ScienceDept [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_role_usage_mi/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_role_usage_mi/Reference.cd new file mode 100644 index 00000000..4e923a9a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_role_usage_mi/Reference.cd @@ -0,0 +1,6 @@ +classdiagram Reference { + class Teacher; + class Department; + + association Teacher -> (departments) Department [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_role_usage_mi/adapter/Teacher.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_role_usage_mi/adapter/Teacher.java new file mode 100644 index 00000000..2a1e8d8d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/association_role_usage_mi/adapter/Teacher.java @@ -0,0 +1,15 @@ +package Concrete; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Teacher"}, template = "${}") +public class Teacher extends TeacherTOP { + + @Adapt(ref = {"Department"}, template = "first${}") + public Department firstDepartment(Department fallback) { + for (Department department : this.departments) { + return department; + } + return fallback; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Concrete.cd index 261cda75..b079d688 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Concrete.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Concrete.cd @@ -1,5 +1,5 @@ -package de.monticore.codeAdaption.evaluation.confCheckingCD; import java.lang.String; +import java.util.Date; classdiagram Concrete { diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Reference.cd index 7b31ec6a..cda8aaca 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Reference.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Reference.cd @@ -1,5 +1,5 @@ -package de.monticore.codeAdaption.evaluation.confCheckingCD; import java.lang.String; +import java.util.Date; classdiagram Reference { diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/Adapter.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/Adapter.cd new file mode 100644 index 00000000..df9d7565 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/Adapter.cd @@ -0,0 +1,10 @@ +classdiagram Adapter { + + interface Target { void operation(); } + + class Adapter implements Target ; + + class Adaptee; + + association Adapter -> Adaptee [1]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/Composition.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/Composition.cd new file mode 100644 index 00000000..eff0f052 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/Composition.cd @@ -0,0 +1,10 @@ +classdiagram Composition { + + interface Component { void execute(); } + + class Leaf implements Component ; + + class Composite implements Component ; + + association Composite -> Component [1..*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/DesignPatterns.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/DesignPatterns.cd new file mode 100644 index 00000000..a2a6825d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/DesignPatterns.cd @@ -0,0 +1,35 @@ +classdiagram DesignPatterns { + + <> + interface Graphic { + <> void render(); + } + + <> + class Circle implements Graphic { + public void render(); + } + + <> + class Rectangle implements Graphic { + public void render(); + } + + <> + class Picture implements Graphic { + public void render(); + } + + association Picture -> Graphic [1..*]; + + <> interface FlexImage { + <> void flex(); + } + + <> + class NPGAdapter implements FlexImage; + + <> class NPGImage; + + association NPGAdapter -> NPGImage [1]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/adapter/Adaptee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/adapter/Adaptee.java new file mode 100644 index 00000000..6db0a593 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/adapter/Adaptee.java @@ -0,0 +1,3 @@ +package DesignPatterns; + +public class Adaptee {} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/adapter/Adapter.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/adapter/Adapter.java new file mode 100644 index 00000000..9d7db36f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/adapter/Adapter.java @@ -0,0 +1,11 @@ +package DesignPatterns; + +import de.monticore.codeAdaption.utils.Adapt; + +public class Adapter implements Target { + + @Adapt(ref = "Target.operation()", template = "${}") + public void operation() { + // do nothing + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/composition/Composite.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/composition/Composite.java new file mode 100644 index 00000000..03100ab9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/composition/Composite.java @@ -0,0 +1,31 @@ +package DesignPatterns; + +import de.monticore.codeAdaption.utils.Adapt; +import java.util.ArrayList; +import java.util.List; + +public class Composite implements Component { + private final List componentList = new ArrayList<>(); + + @Adapt(ref = "Component.execute()", template = "${}") + public void execute() { + for (Component component : componentList) { + component.execute(); + } + } + + @Adapt(ref = "Component", template = "add${}") + public void addComponent(Component component) { + componentList.add(component); + } + + @Adapt(ref = "Component", template = "remove${}") + public void removeComponent(Component component) { + componentList.remove(component); + } + + @Adapt(ref = "Component", template = "get${}") + public List getComponent() { + return componentList; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/composition/Leaf.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/composition/Leaf.java new file mode 100644 index 00000000..26ba2a63 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/design_patterns/hwc/composition/Leaf.java @@ -0,0 +1,11 @@ +package DesignPatterns; + +import de.monticore.codeAdaption.utils.Adapt; + +public class Leaf implements Component { + + @Adapt(ref = "Component.execute()", template = "${}") + public void execute() { + // do nothing + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/single_file_multi_pattern/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/single_file_multi_pattern/Concrete.cd new file mode 100644 index 00000000..7763f0ca --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/single_file_multi_pattern/Concrete.cd @@ -0,0 +1,10 @@ +import java.lang.String; + +classdiagram Concrete { + <> class MyClass { + <> String renamedField; + <> void renamedMethod(); + <> String pattern1Shared; + <> String pattern2Shared; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/single_file_multi_pattern/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/single_file_multi_pattern/Reference.cd new file mode 100644 index 00000000..31e9af06 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/single_file_multi_pattern/Reference.cd @@ -0,0 +1,9 @@ +import java.lang.String; + +classdiagram Reference { + class MyClass { + String oldField; + void oldMethod(); + String sharedField; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/single_file_multi_pattern/reference/MyClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/single_file_multi_pattern/reference/MyClass.java new file mode 100644 index 00000000..4d08f1e6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/single_file_multi_pattern/reference/MyClass.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.evaluation.single_file_multi_pattern; + +public class MyClass { + private String oldField; + private String sharedField; + public void oldMethod() { } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Concrete.cd index 065c8f96..1450357e 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Concrete.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Concrete.cd @@ -1,5 +1,5 @@ -package de.monticore.codeAdaption.evaluation.testcase_1; import java.lang.String; +import java.util.Date; classdiagram Concrete { diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Reference.cd index dfd8aef5..632a9473 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Reference.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Reference.cd @@ -1,5 +1,5 @@ -package de.monticore.codeAdaption.evaluation.testcase_1; import java.lang.String; +import java.util.Date; classdiagram Reference { diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/Concrete.cd new file mode 100644 index 00000000..298191eb --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/Concrete.cd @@ -0,0 +1,22 @@ +import java.lang.String; + +classdiagram Concrete { + + <> class DatabaseConnection { + <> String connectionString; + <> boolean isConnected; + void connect(); + void disconnect(); + } + + <> class Logger { + <> String logFile; + void log(String message); + } + + class Application { + DatabaseConnection db; + Logger logger; + void initialize(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/Reference.cd new file mode 100644 index 00000000..db17ee21 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/Reference.cd @@ -0,0 +1,8 @@ + +classdiagram Reference { + class Singleton { + static Singleton instance; + static Singleton getInstance(); + any attribute; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/adapter/Singleton.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/adapter/Singleton.java new file mode 100644 index 00000000..bc458f17 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/adapter/Singleton.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.evaluation.testcase_10_singleton_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Singleton"}, template = "${}") +public class Singleton { + private static Singleton instance; + + @Adapt(ref = {"Singleton.instance"}, template = "get${cap_first}") + public static Singleton getInstance() { + if (instance == null) { + instance = new Singleton(); + } + return instance; + } + + private Singleton() { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/concrete/Application.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/concrete/Application.java new file mode 100644 index 00000000..a71bb9e2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/concrete/Application.java @@ -0,0 +1,27 @@ +package de.monticore.codeAdaption.evaluation.testcase_10_singleton_pattern; + +/** + * Application domain class + */ +public class Application { + private DatabaseConnection db; + private Logger logger; + + public Application() { + this.db = new DatabaseConnection(); + this.logger = new Logger(); + } + + public Application(DatabaseConnection db, Logger logger) { + this.db = db; + this.logger = logger; + } + + public void initialize() { + db.connect(); + logger.log("Application initialized"); + } + + public DatabaseConnection getDb() { return db; } + public Logger getLogger() { return logger; } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/concrete/DatabaseConnection.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/concrete/DatabaseConnection.java new file mode 100644 index 00000000..42c03a20 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/concrete/DatabaseConnection.java @@ -0,0 +1,30 @@ +package de.monticore.codeAdaption.evaluation.testcase_10_singleton_pattern; + +/** + * DatabaseConnection domain class + */ +public class DatabaseConnection { + private String connectionString; + private boolean isConnected; + + public DatabaseConnection() { + this.connectionString = "jdbc:default"; + this.isConnected = false; + } + + public DatabaseConnection(String connectionString) { + this.connectionString = connectionString; + this.isConnected = false; + } + + public String getConnectionString() { return connectionString; } + public boolean isConnected() { return isConnected; } + + public void connect() { + this.isConnected = true; + } + + public void disconnect() { + this.isConnected = false; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/concrete/Logger.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/concrete/Logger.java new file mode 100644 index 00000000..4bd92142 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_10_singleton_pattern/concrete/Logger.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.evaluation.testcase_10_singleton_pattern; + +/** + * Logger domain class + */ +public class Logger { + private String logFile; + + public Logger() { + this.logFile = "application.log"; + } + + public Logger(String logFile) { + this.logFile = logFile; + } + + public String getLogFile() { return logFile; } + + public void log(String message) { + System.out.println("LOG: " + message); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/Concrete.cd new file mode 100644 index 00000000..2e4e8f07 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/Concrete.cd @@ -0,0 +1,33 @@ +import java.lang.String; + +classdiagram Concrete { + + <> abstract class DataProcessor { + String source; + String destination; + <> abstract void readData(); + <> abstract void transformData(); + <> void validateData(); + } + + <> class CSVProcessor extends DataProcessor { + String delimiter; + <> void readData(); + <> void transformData(); + <> void validateData(); + } + + <> class JSONProcessor extends DataProcessor { + boolean prettyPrint; + <> void readData(); + <> void transformData(); + <> void validateData(); + } + + <> class XMLProcessor extends DataProcessor { + String encoding; + <> void readData(); + <> void transformData(); + <> void validateData(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/Reference.cd new file mode 100644 index 00000000..c43a6e3a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/Reference.cd @@ -0,0 +1,15 @@ + +classdiagram Reference { + abstract class AbstractClass { + void templateMethod(); + abstract void primitiveOperation1(); + abstract void primitiveOperation2(); + void hook(); + } + + class ConcreteClass extends AbstractClass { + void primitiveOperation1(); + void primitiveOperation2(); + void hook(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/adapter/AbstractClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/adapter/AbstractClass.java new file mode 100644 index 00000000..f0d9da80 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/adapter/AbstractClass.java @@ -0,0 +1,26 @@ +package de.monticore.codeAdaption.evaluation.testcase_11_template_method_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"AbstractClass"}, template = "${}") +public abstract class AbstractClass { + + @Adapt(ref = {"AbstractClass.templateMethod"}, template = "${}") + public void templateMethod() { + primitiveOperation1(); + primitiveOperation2(); + hook(); + } + + @Adapt(ref = {"AbstractClass.primitiveOperation1"}, template = "${}") + public abstract void primitiveOperation1(); + + @Adapt(ref = {"AbstractClass.primitiveOperation2"}, template = "${}") + public abstract void primitiveOperation2(); + + @Adapt(ref = {"AbstractClass.hook"}, template = "${}") + public void hook() { + // Default implementation + System.out.println("Hook"); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/CSVProcessor.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/CSVProcessor.java new file mode 100644 index 00000000..760e0f8d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/CSVProcessor.java @@ -0,0 +1,30 @@ +package de.monticore.codeAdaption.evaluation.testcase_11_template_method_pattern; + +/** + * CSVProcessor concrete implementation of DataProcessor + */ +public class CSVProcessor extends DataProcessor { + private String delimiter; + + public CSVProcessor() { + this.delimiter = ","; + } + + public CSVProcessor(String delimiter) { + this.delimiter = delimiter; + } + + public String getDelimiter() { return delimiter; } + + public void readData() { + System.out.println("Reading CSV data"); + } + + public void transformData() { + System.out.println("Transforming CSV data"); + } + + public void validateData() { + System.out.println("Validating CSV format"); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/DataProcessor.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/DataProcessor.java new file mode 100644 index 00000000..8a46d910 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/DataProcessor.java @@ -0,0 +1,29 @@ +package de.monticore.codeAdaption.evaluation.testcase_11_template_method_pattern; + +/** + * DataProcessor abstract class + */ +public abstract class DataProcessor { + private String source; + private String destination; + + public DataProcessor() { + this.source = "default"; + this.destination = "default"; + } + + public DataProcessor(String source, String destination) { + this.source = source; + this.destination = destination; + } + + public String getSource() { return source; } + public String getDestination() { return destination; } + + public abstract void readData(); + public abstract void transformData(); + + public void validateData() { + System.out.println("Validating data..."); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/JSONProcessor.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/JSONProcessor.java new file mode 100644 index 00000000..e28c6044 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/JSONProcessor.java @@ -0,0 +1,30 @@ +package de.monticore.codeAdaption.evaluation.testcase_11_template_method_pattern; + +/** + * JSONProcessor concrete implementation of DataProcessor + */ +public class JSONProcessor extends DataProcessor { + private boolean prettyPrint; + + public JSONProcessor() { + this.prettyPrint = false; + } + + public JSONProcessor(boolean prettyPrint) { + this.prettyPrint = prettyPrint; + } + + public boolean isPrettyPrint() { return prettyPrint; } + + public void readData() { + System.out.println("Reading JSON data"); + } + + public void transformData() { + System.out.println("Transforming JSON data"); + } + + public void validateData() { + System.out.println("Validating JSON schema"); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/XMLProcessor.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/XMLProcessor.java new file mode 100644 index 00000000..b458d43c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_11_template_method_pattern/concrete/XMLProcessor.java @@ -0,0 +1,30 @@ +package de.monticore.codeAdaption.evaluation.testcase_11_template_method_pattern; + +/** + * XMLProcessor concrete implementation of DataProcessor + */ +public class XMLProcessor extends DataProcessor { + private String encoding; + + public XMLProcessor() { + this.encoding = "UTF-8"; + } + + public XMLProcessor(String encoding) { + this.encoding = encoding; + } + + public String getEncoding() { return encoding; } + + public void readData() { + System.out.println("Reading XML data"); + } + + public void transformData() { + System.out.println("Transforming XML data"); + } + + public void validateData() { + System.out.println("Validating XML DTD"); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/Concrete.cd new file mode 100644 index 00000000..e29ccfe2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/Concrete.cd @@ -0,0 +1,35 @@ +import java.lang.String; + +classdiagram Concrete { + + <> class ConfigurationManager { + <> String environment; + <> ConfigStorageStrategy storageStrategy; + <> void setStorageStrategy(ConfigStorageStrategy strategy); + <> void saveConfig(String key, String value); + <> String loadConfig(String key); + } + + <> interface ConfigStorageStrategy { + <> void save(String key, String value); + <> String load(String key); + } + + <> class FileStorageStrategy implements ConfigStorageStrategy { + String basePath; + <> void save(String key, String value); + <> String load(String key); + } + + <> class DatabaseStorageStrategy implements ConfigStorageStrategy { + String connectionString; + <> void save(String key, String value); + <> String load(String key); + } + + <> class CloudStorageStrategy implements ConfigStorageStrategy { + String bucketName; + <> void save(String key, String value); + <> String load(String key); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/Reference.cd new file mode 100644 index 00000000..35840b03 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/Reference.cd @@ -0,0 +1,22 @@ + +classdiagram Reference { + class Singleton { + static Singleton instance; + static Singleton getInstance(); + any attribute; + } + + class Context { + Strategy strategy; + void setStrategy(Strategy strategy); + void execute(); + } + + interface Strategy { + void execute(); + } + + class ConcreteStrategy implements Strategy { + void execute(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/adapter/Context.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/adapter/Context.java new file mode 100644 index 00000000..77fda621 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/adapter/Context.java @@ -0,0 +1,18 @@ +package de.monticore.codeAdaption.evaluation.testcase_12_strategy_singleton_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Context"}, template = "${}") +public class Context { + private Strategy strategy; + + @Adapt(ref = {"Context.strategy"}, template = "set${cap_first}") + public void setStrategy(Strategy strategy) { + this.strategy = strategy; + } + + @Adapt(ref = {"Context.execute"}, template = "execute") + public void execute() { + strategy.execute(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/adapter/Singleton.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/adapter/Singleton.java new file mode 100644 index 00000000..29bd4d63 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/adapter/Singleton.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.evaluation.testcase_12_strategy_singleton_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Singleton"}, template = "${}") +public class Singleton { + private static Singleton instance; + + @Adapt(ref = {"Singleton.instance"}, template = "get${cap_first}") + public static Singleton getInstance() { + if (instance == null) { + instance = new Singleton(); + } + return instance; + } + + private Singleton() { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/adapter/Strategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/adapter/Strategy.java new file mode 100644 index 00000000..a05c3599 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/adapter/Strategy.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.evaluation.testcase_12_strategy_singleton_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Strategy"}, template = "${}") +public interface Strategy { + + @Adapt(ref = {"Strategy.execute"}, template = "execute") + void execute(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/CloudStorageStrategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/CloudStorageStrategy.java new file mode 100644 index 00000000..3837c97a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/CloudStorageStrategy.java @@ -0,0 +1,27 @@ +package de.monticore.codeAdaption.evaluation.testcase_12_strategy_singleton; + +/** + * CloudStorageStrategy concrete implementation + */ +public class CloudStorageStrategy implements ConfigStorageStrategy { + private String bucketName; + + public CloudStorageStrategy() { + this.bucketName = "default-bucket"; + } + + public CloudStorageStrategy(String bucketName) { + this.bucketName = bucketName; + } + + public String getBucketName() { return bucketName; } + + public void save(String key, String value) { + System.out.println("Saving to cloud: " + key + " = " + value); + } + + public String load(String key) { + System.out.println("Loading from cloud: " + key); + return "cloud_value"; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/ConfigStorageStrategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/ConfigStorageStrategy.java new file mode 100644 index 00000000..fd10b20e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/ConfigStorageStrategy.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.evaluation.testcase_12_strategy_singleton; + +/** + * ConfigStorageStrategy interface + */ +public interface ConfigStorageStrategy { + void save(String key, String value); + String load(String key); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/ConfigurationManager.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/ConfigurationManager.java new file mode 100644 index 00000000..358d710f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/ConfigurationManager.java @@ -0,0 +1,34 @@ +package de.monticore.codeAdaption.evaluation.testcase_12_strategy_singleton; + +/** + * ConfigurationManager domain class + */ +public class ConfigurationManager { + private String environment; + private ConfigStorageStrategy storageStrategy; + + public ConfigurationManager() { + this.environment = "production"; + this.storageStrategy = new FileStorageStrategy(); + } + + public ConfigurationManager(String environment, ConfigStorageStrategy storageStrategy) { + this.environment = environment; + this.storageStrategy = storageStrategy; + } + + public String getEnvironment() { return environment; } + public ConfigStorageStrategy getStorageStrategy() { return storageStrategy; } + + public void setStorageStrategy(ConfigStorageStrategy strategy) { + this.storageStrategy = strategy; + } + + public void saveConfig(String key, String value) { + storageStrategy.save(key, value); + } + + public String loadConfig(String key) { + return storageStrategy.load(key); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/DatabaseStorageStrategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/DatabaseStorageStrategy.java new file mode 100644 index 00000000..d6fc0e4a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/DatabaseStorageStrategy.java @@ -0,0 +1,27 @@ +package de.monticore.codeAdaption.evaluation.testcase_12_strategy_singleton; + +/** + * DatabaseStorageStrategy concrete implementation + */ +public class DatabaseStorageStrategy implements ConfigStorageStrategy { + private String connectionString; + + public DatabaseStorageStrategy() { + this.connectionString = "jdbc:default"; + } + + public DatabaseStorageStrategy(String connectionString) { + this.connectionString = connectionString; + } + + public String getConnectionString() { return connectionString; } + + public void save(String key, String value) { + System.out.println("Saving to database: " + key + " = " + value); + } + + public String load(String key) { + System.out.println("Loading from database: " + key); + return "db_value"; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/FileStorageStrategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/FileStorageStrategy.java new file mode 100644 index 00000000..82eb4ba2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_12_strategy_singleton_pattern/concrete/FileStorageStrategy.java @@ -0,0 +1,27 @@ +package de.monticore.codeAdaption.evaluation.testcase_12_strategy_singleton; + +/** + * FileStorageStrategy concrete implementation + */ +public class FileStorageStrategy implements ConfigStorageStrategy { + private String basePath; + + public FileStorageStrategy() { + this.basePath = "/config"; + } + + public FileStorageStrategy(String basePath) { + this.basePath = basePath; + } + + public String getBasePath() { return basePath; } + + public void save(String key, String value) { + System.out.println("Saving to file: " + key + " = " + value); + } + + public String load(String key) { + System.out.println("Loading from file: " + key); + return "file_value"; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Concrete.cd new file mode 100644 index 00000000..c5f6f16c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Concrete.cd @@ -0,0 +1,40 @@ +import java.lang.String; + +classdiagram Concrete { + + <> abstract class DataPipeline { + String pipelineName; + String source; + <> abstract void extractData(); + <> abstract void processData(); + <> abstract void loadData(); + } + + <> class SalesDataPipeline extends DataPipeline { + String crmSystem; + <> void extractData(); + <> void processData(); + <> void loadData(); + } + + <> class InventoryDataPipeline extends DataPipeline { + String erpSystem; + <> void extractData(); + <> void processData(); + <> void loadData(); + } + + <> interface PipelineObserver { + <> void onPipelineStage(String stage); + } + + <> class LoggingObserver implements PipelineObserver { + String logLevel; + <> void onPipelineStage(String stage); + } + + <> class MetricsObserver implements PipelineObserver { + String metricsEndpoint; + <> void onPipelineStage(String stage); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Reference.cd new file mode 100644 index 00000000..c416ed1c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/Reference.cd @@ -0,0 +1,28 @@ +import java.util.List; + + +classdiagram Reference { + abstract class AbstractClass { + void templateMethod(); + abstract void primitiveOperation1(); + abstract void primitiveOperation2(); + void hook(); + } + + class Subject { + List observers; + boolean subscribe(Observer o); + boolean unsubscribe(Observer o); + void notifyAll(); + } + + interface Observer { + void update(); + } + + class ConcreteClass extends AbstractClass { + void primitiveOperation1(); + void primitiveOperation2(); + void hook(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/adapter/AbstractClass.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/adapter/AbstractClass.java new file mode 100644 index 00000000..011a7a2a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/adapter/AbstractClass.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.evaluation.testcase_13_template_observer_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"AbstractClass"}, template = "${}") +public abstract class AbstractClass { + + @Adapt(ref = {"AbstractClass.templateMethod"}, template = "templateMethod") + public void templateMethod() { + primitiveOperation1(); + primitiveOperation2(); + hook(); + } + + @Adapt(ref = {"AbstractClass.primitiveOperation1"}, template = "primitiveOperation1") + public abstract void primitiveOperation1(); + + @Adapt(ref = {"AbstractClass.primitiveOperation2"}, template = "primitiveOperation2") + public abstract void primitiveOperation2(); + + @Adapt(ref = {"AbstractClass.hook"}, template = "hook") + public void hook() { + // Default implementation + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/adapter/Observer.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/adapter/Observer.java new file mode 100644 index 00000000..624fe8f1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/adapter/Observer.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.evaluation.testcase_13_template_observer_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Observer"}, template = "${}") +public interface Observer { + + @Adapt(ref = {"Observer.update"}, template = "update") + void update(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/adapter/Subject.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/adapter/Subject.java new file mode 100644 index 00000000..da25c78f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/adapter/Subject.java @@ -0,0 +1,27 @@ +package de.monticore.codeAdaption.evaluation.testcase_13_template_observer_pattern; + +import de.monticore.codeAdaption.utils.Adapt; +import java.util.List; +import java.util.ArrayList; + +@Adapt(ref = {"Subject"}, template = "${}") +public class Subject { + private List observers = new ArrayList<>(); + + @Adapt(ref = {"Subject.subscribe"}, template = "subscribe") + public boolean subscribe(Observer o) { + return observers.add(o); + } + + @Adapt(ref = {"Subject.unsubscribe"}, template = "unsubscribe") + public boolean unsubscribe(Observer o) { + return observers.remove(o); + } + + @Adapt(ref = {"Subject.notifyAll"}, template = "notifyAll") + public void notifyAll() { + for (Observer observer : observers) { + observer.update(); + } + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/DataPipeline.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/DataPipeline.java new file mode 100644 index 00000000..cda80417 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/DataPipeline.java @@ -0,0 +1,26 @@ +package de.monticore.codeAdaption.evaluation.testcase_13_template_observer; + +/** + * DataPipeline abstract class + */ +public abstract class DataPipeline { + private String pipelineName; + private String source; + + public DataPipeline() { + this.pipelineName = "default"; + this.source = "default"; + } + + public DataPipeline(String pipelineName, String source) { + this.pipelineName = pipelineName; + this.source = source; + } + + public String getPipelineName() { return pipelineName; } + public String getSource() { return source; } + + public abstract void extractData(); + public abstract void processData(); + public abstract void loadData(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/InventoryDataPipeline.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/InventoryDataPipeline.java new file mode 100644 index 00000000..1286aed8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/InventoryDataPipeline.java @@ -0,0 +1,30 @@ +package de.monticore.codeAdaption.evaluation.testcase_13_template_observer; + +/** + * InventoryDataPipeline concrete implementation of DataPipeline + */ +public class InventoryDataPipeline extends DataPipeline { + private String erpSystem; + + public InventoryDataPipeline() { + this.erpSystem = "SAP"; + } + + public InventoryDataPipeline(String erpSystem) { + this.erpSystem = erpSystem; + } + + public String getErpSystem() { return erpSystem; } + + public void extractData() { + System.out.println("Extracting inventory data from ERP"); + } + + public void processData() { + System.out.println("Processing inventory data with stock rules"); + } + + public void loadData() { + System.out.println("Loading processed inventory data to warehouse"); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/LoggingObserver.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/LoggingObserver.java new file mode 100644 index 00000000..73a361c3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/LoggingObserver.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.evaluation.testcase_13_template_observer; + +/** + * LoggingObserver concrete implementation of PipelineObserver + */ +public class LoggingObserver implements PipelineObserver { + private String logLevel; + + public LoggingObserver() { + this.logLevel = "INFO"; + } + + public LoggingObserver(String logLevel) { + this.logLevel = logLevel; + } + + public String getLogLevel() { return logLevel; } + + public void onPipelineStage(String stage) { + System.out.println("[LOG] Pipeline stage: " + stage); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/MetricsObserver.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/MetricsObserver.java new file mode 100644 index 00000000..da9ca392 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/MetricsObserver.java @@ -0,0 +1,22 @@ +package de.monticore.codeAdaption.evaluation.testcase_13_template_observer; + +/** + * MetricsObserver concrete implementation of PipelineObserver + */ +public class MetricsObserver implements PipelineObserver { + private String metricsEndpoint; + + public MetricsObserver() { + this.metricsEndpoint = "/metrics"; + } + + public MetricsObserver(String metricsEndpoint) { + this.metricsEndpoint = metricsEndpoint; + } + + public String getMetricsEndpoint() { return metricsEndpoint; } + + public void onPipelineStage(String stage) { + System.out.println("[METRICS] Recording metrics for stage: " + stage); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/PipelineObserver.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/PipelineObserver.java new file mode 100644 index 00000000..52e54a9c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/PipelineObserver.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.evaluation.testcase_13_template_observer; + +/** + * PipelineObserver interface + */ +public interface PipelineObserver { + void onPipelineStage(String stage); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/SalesDataPipeline.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/SalesDataPipeline.java new file mode 100644 index 00000000..dd844b56 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_13_template_observer_pattern/concrete/SalesDataPipeline.java @@ -0,0 +1,30 @@ +package de.monticore.codeAdaption.evaluation.testcase_13_template_observer; + +/** + * SalesDataPipeline concrete implementation of DataPipeline + */ +public class SalesDataPipeline extends DataPipeline { + private String crmSystem; + + public SalesDataPipeline() { + this.crmSystem = "Salesforce"; + } + + public SalesDataPipeline(String crmSystem) { + this.crmSystem = crmSystem; + } + + public String getCrmSystem() { return crmSystem; } + + public void extractData() { + System.out.println("Extracting sales data from CRM"); + } + + public void processData() { + System.out.println("Processing sales data with business rules"); + } + + public void loadData() { + System.out.println("Loading processed sales data to warehouse"); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/Concrete.cd new file mode 100644 index 00000000..ff939965 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/Concrete.cd @@ -0,0 +1,22 @@ +import java.lang.String; + +classdiagram Concrete { + <> interface ShippingPort { + <> boolean ship(String label, boolean insured); + } + + <> class LegacyCarrier { + String endpoint; + <> boolean dispatch(String label, boolean insured); + } + + <> class CarrierAdapter implements ShippingPort { + LegacyCarrier carrier; + CarrierAdapter(LegacyCarrier carrier); + <> boolean ship(String label, boolean insured); + } + + <> class ShippingFactory { + <> ShippingPort createCarrier(LegacyCarrier carrier); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/Reference.cd new file mode 100644 index 00000000..ecf640d4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/Reference.cd @@ -0,0 +1,21 @@ +import java.lang.String; + +classdiagram Reference { + interface Target { + boolean request(String payload); + } + + class Adaptee { + boolean specificRequest(String payload); + } + + class Adapter implements Target { + Adaptee adaptee; + Adapter(Adaptee adaptee); + boolean request(String payload); + } + + abstract class Creator { + abstract Target create(Adaptee adaptee); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Adaptee.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Adaptee.java new file mode 100644 index 00000000..e52d81bf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Adaptee.java @@ -0,0 +1,11 @@ +package de.monticore.codeAdaption.evaluation.testcase_14_adapter_factory_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = "Adaptee", template = "${}") +public class Adaptee { + @Adapt(ref = "Adaptee.specificRequest", template = "${}") + public boolean specificRequest(String payload) { + return false; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Adapter.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Adapter.java new file mode 100644 index 00000000..145bf988 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Adapter.java @@ -0,0 +1,18 @@ +package de.monticore.codeAdaption.evaluation.testcase_14_adapter_factory_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = "Adapter", template = "${}") +public class Adapter implements Target { + @Adapt(ref = "Adapter.adaptee", template = "${}") + private Adaptee adaptee; + + public Adapter(Adaptee adaptee) { + this.adaptee = adaptee; + } + + @Adapt(ref = "Target.request", template = "${}") + public boolean request(String payload) { + return adaptee.specificRequest(payload); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Creator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Creator.java new file mode 100644 index 00000000..b33a2625 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Creator.java @@ -0,0 +1,11 @@ +package de.monticore.codeAdaption.evaluation.testcase_14_adapter_factory_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = "Creator", template = "${}") +public abstract class Creator { + @Adapt(ref = "Creator.create", template = "${}") + public Target create(Adaptee adaptee) { + return new Adapter(adaptee); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Target.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Target.java new file mode 100644 index 00000000..cc9eb0a8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/adapter/Target.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.evaluation.testcase_14_adapter_factory_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = "Target", template = "${}") +public interface Target { + @Adapt(ref = "Target.request", template = "${}") + boolean request(String payload); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/CarrierAdapter.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/CarrierAdapter.java new file mode 100644 index 00000000..c2ea3a5b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/CarrierAdapter.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.evaluation.testcase_14_adapter_factory_combined.concrete; + +public class CarrierAdapter implements ShippingPort { + private final LegacyCarrier carrier; + + public CarrierAdapter(LegacyCarrier carrier) { + this.carrier = carrier; + } + + @Override + public boolean ship(String label, boolean insured) { + return carrier.dispatch(label, insured); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/LegacyCarrier.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/LegacyCarrier.java new file mode 100644 index 00000000..bbdb2cf9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/LegacyCarrier.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.evaluation.testcase_14_adapter_factory_combined.concrete; + +public class LegacyCarrier { + String endpoint; + + public boolean dispatch(String label, boolean insured) { + return label != null && !label.isBlank(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/ShippingFactory.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/ShippingFactory.java new file mode 100644 index 00000000..40791398 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/ShippingFactory.java @@ -0,0 +1,7 @@ +package de.monticore.codeAdaption.evaluation.testcase_14_adapter_factory_combined.concrete; + +public class ShippingFactory { + public ShippingPort createCarrier(LegacyCarrier carrier) { + return new CarrierAdapter(carrier); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/ShippingPort.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/ShippingPort.java new file mode 100644 index 00000000..91f2c758 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_14_adapter_factory_combined/concrete/ShippingPort.java @@ -0,0 +1,5 @@ +package de.monticore.codeAdaption.evaluation.testcase_14_adapter_factory_combined.concrete; + +public interface ShippingPort { + boolean ship(String label, boolean insured); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/Concrete.cd new file mode 100644 index 00000000..96ea5a44 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/Concrete.cd @@ -0,0 +1,43 @@ +import java.lang.String; +import java.util.List; + +classdiagram Concrete { + <> interface Renderable { + <> String render(int depth); + } + + <> class TextNode implements Renderable { + String text; + <> String render(int depth); + } + + <> class ImageNode implements Renderable { + String source; + <> String render(int depth); + } + + <> class GroupNode implements Renderable { + List nodes; + <> void attach(Renderable node); + <> void detach(Renderable node); + <> String render(int depth); + } + + <> abstract class RenderDecorator implements Renderable { + Renderable wrapped; + RenderDecorator(Renderable wrapped); + <> String render(int depth); + } + + <> class BorderDecorator extends RenderDecorator { + String borderStyle; + BorderDecorator(Renderable wrapped); + <> String render(int depth); + } + + <> class ShadowDecorator extends RenderDecorator { + int radius; + ShadowDecorator(Renderable wrapped); + <> String render(int depth); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/Reference.cd new file mode 100644 index 00000000..2116192e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/Reference.cd @@ -0,0 +1,26 @@ +import java.lang.String; +import java.util.List; + + +classdiagram Reference { + interface Component { + String operation(); + } + + class Leaf implements Component { + String operation(); + } + + class Composite implements Component { + List children; + void add(Component component); + void remove(Component component); + String operation(); + } + + abstract class Decorator implements Component { + Component wrapped; + Decorator(Component wrapped); + String operation(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Component.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Component.java new file mode 100644 index 00000000..5c0de4de --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Component.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = "Component", template = "${}") +public interface Component { + @Adapt(ref = "Component.operation", template = "${}") + String operation(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Composite.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Composite.java new file mode 100644 index 00000000..81efad41 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Composite.java @@ -0,0 +1,31 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; +import java.util.ArrayList; +import java.util.List; + +@Adapt(ref = "Composite", template = "${}") +public class Composite implements Component { + @Adapt(ref = "Composite.children", template = "${}") + private List children = new ArrayList<>(); + + @Adapt(ref = "Composite.add", template = "${}") + public void add(Component component) { + children.add(component); + } + + @Adapt(ref = "Composite.remove", template = "${}") + public void remove(Component component) { + children.remove(component); + } + + @Override + @Adapt(ref = "Component.operation", template = "${}") + public String operation() { + StringBuilder builder = new StringBuilder(); + for (Component child : children) { + builder.append(child.operation()); + } + return builder.toString(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Decorator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Decorator.java new file mode 100644 index 00000000..cd28e239 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Decorator.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = "Decorator", template = "${}") +public abstract class Decorator implements Component { + @Adapt(ref = "Decorator.wrapped", template = "${}") + protected Component wrapped; + + public Decorator(Component wrapped) { + this.wrapped = wrapped; + } + + @Override + @Adapt(ref = "Component.operation", template = "${}") + public String operation() { + return wrapped.operation(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Leaf.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Leaf.java new file mode 100644 index 00000000..089d5be2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/adapter/Leaf.java @@ -0,0 +1,12 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = "Leaf", template = "${}") +public class Leaf implements Component { + @Override + @Adapt(ref = "Component.operation", template = "${}") + public String operation() { + return ""; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/BorderDecorator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/BorderDecorator.java new file mode 100644 index 00000000..639ea08d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/BorderDecorator.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.concrete; + +public class BorderDecorator extends RenderDecorator { + String borderStyle; + + public BorderDecorator(Renderable wrapped) { + super(wrapped); + } + + @Override + public String render(int depth) { + return "[" + wrapped.render(depth) + "]"; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/GroupNode.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/GroupNode.java new file mode 100644 index 00000000..6bf7ce10 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/GroupNode.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.concrete; + +import java.util.ArrayList; +import java.util.List; + +public class GroupNode implements Renderable { + private final List nodes = new ArrayList<>(); + + public void attach(Renderable node) { + nodes.add(node); + } + + public void detach(Renderable node) { + nodes.remove(node); + } + + @Override + public String render(int depth) { + StringBuilder result = new StringBuilder(); + for (Renderable node : nodes) { + result.append(node.render(depth + 1)); + } + return result.toString(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/ImageNode.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/ImageNode.java new file mode 100644 index 00000000..661966ff --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/ImageNode.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.concrete; + +public class ImageNode implements Renderable { + String source; + + @Override + public String render(int depth) { + return source == null ? "" : source; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/RenderDecorator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/RenderDecorator.java new file mode 100644 index 00000000..75a9b61e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/RenderDecorator.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.concrete; + +public abstract class RenderDecorator implements Renderable { + protected final Renderable wrapped; + + protected RenderDecorator(Renderable wrapped) { + this.wrapped = wrapped; + } + + @Override + public String render(int depth) { + return wrapped.render(depth); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/Renderable.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/Renderable.java new file mode 100644 index 00000000..9eaa05a6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/Renderable.java @@ -0,0 +1,5 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.concrete; + +public interface Renderable { + String render(int depth); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/ShadowDecorator.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/ShadowDecorator.java new file mode 100644 index 00000000..7d91beef --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/ShadowDecorator.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.concrete; + +public class ShadowDecorator extends RenderDecorator { + int radius; + + public ShadowDecorator(Renderable wrapped) { + super(wrapped); + } + + @Override + public String render(int depth) { + return wrapped.render(depth) + "#shadow"; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/TextNode.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/TextNode.java new file mode 100644 index 00000000..df1b0bfe --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_15_composite_decorator_combined/concrete/TextNode.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.evaluation.testcase_15_composite_decorator_combined.concrete; + +public class TextNode implements Renderable { + String text; + + @Override + public String render(int depth) { + return text == null ? "" : text; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/Concrete.cd new file mode 100644 index 00000000..c8afc23a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/Concrete.cd @@ -0,0 +1,32 @@ +import java.lang.String; +import java.util.List; + +classdiagram Concrete { + <> class EventBus { + List listeners; + String lastEvent; + <> void subscribe(WorkflowCommand command); + <> void unsubscribe(WorkflowCommand command); + <> void publish(String event); + } + + <> interface WorkflowCommand { + <> void run(String event, boolean async); + } + + <> class EmailCommand implements WorkflowCommand { + String address; + <> void run(String event, boolean async); + } + + <> class SmsCommand implements WorkflowCommand { + String phoneNumber; + <> void run(String event, boolean async); + } + + <> class CommandQueue { + List backlog; + <> void schedule(WorkflowCommand command); + <> void drain(String event); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/Reference.cd new file mode 100644 index 00000000..2c82af32 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/Reference.cd @@ -0,0 +1,25 @@ +import java.util.List; + + +classdiagram Reference { + class Subject { + List observers; + void attach(Observer observer); + void detach(Observer observer); + void notifyAll(); + } + + interface Observer { + void update(); + } + + interface Command { + void execute(); + } + + class Invoker { + List commands; + void enqueue(Command command); + void runAll(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Command.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Command.java new file mode 100644 index 00000000..da85b472 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Command.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.evaluation.testcase_16_observer_command_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = "Command", template = "${}") +public interface Command { + @Adapt(ref = "Command.execute", template = "${}") + void execute(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Invoker.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Invoker.java new file mode 100644 index 00000000..3b292c1b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Invoker.java @@ -0,0 +1,23 @@ +package de.monticore.codeAdaption.evaluation.testcase_16_observer_command_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; +import java.util.ArrayList; +import java.util.List; + +@Adapt(ref = "Invoker", template = "${}") +public class Invoker { + @Adapt(ref = "Invoker.commands", template = "${}") + private List commands = new ArrayList<>(); + + @Adapt(ref = "Invoker.enqueue", template = "${}") + public void enqueue(Command command) { + commands.add(command); + } + + @Adapt(ref = "Invoker.runAll", template = "${}") + public void runAll() { + for (Command command : commands) { + command.execute(); + } + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Observer.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Observer.java new file mode 100644 index 00000000..b156c830 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Observer.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.evaluation.testcase_16_observer_command_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = "Observer", template = "${}") +public interface Observer { + @Adapt(ref = "Observer.update", template = "${}") + void update(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Subject.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Subject.java new file mode 100644 index 00000000..72177ec3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/adapter/Subject.java @@ -0,0 +1,28 @@ +package de.monticore.codeAdaption.evaluation.testcase_16_observer_command_combined.adapter; + +import de.monticore.codeAdaption.utils.Adapt; +import java.util.ArrayList; +import java.util.List; + +@Adapt(ref = "Subject", template = "${}") +public class Subject { + @Adapt(ref = "Subject.observers", template = "${}") + private List observers = new ArrayList<>(); + + @Adapt(ref = "Subject.attach", template = "${}") + public void attach(Observer observer) { + observers.add(observer); + } + + @Adapt(ref = "Subject.detach", template = "${}") + public void detach(Observer observer) { + observers.remove(observer); + } + + @Adapt(ref = "Subject.notifyAll", template = "${}") + public void notifyAllObservers() { + for (Observer observer : observers) { + observer.update(); + } + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/CommandQueue.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/CommandQueue.java new file mode 100644 index 00000000..dee6d50f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/CommandQueue.java @@ -0,0 +1,18 @@ +package de.monticore.codeAdaption.evaluation.testcase_16_observer_command_combined.concrete; + +import java.util.ArrayList; +import java.util.List; + +public class CommandQueue { + private final List backlog = new ArrayList<>(); + + public void schedule(WorkflowCommand command) { + backlog.add(command); + } + + public void drain(String event) { + for (WorkflowCommand command : backlog) { + command.run(event, false); + } + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/EmailCommand.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/EmailCommand.java new file mode 100644 index 00000000..985c72a7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/EmailCommand.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.evaluation.testcase_16_observer_command_combined.concrete; + +public class EmailCommand implements WorkflowCommand { + String address; + + @Override + public void run(String event, boolean async) { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/EventBus.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/EventBus.java new file mode 100644 index 00000000..41ae7a5b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/EventBus.java @@ -0,0 +1,24 @@ +package de.monticore.codeAdaption.evaluation.testcase_16_observer_command_combined.concrete; + +import java.util.ArrayList; +import java.util.List; + +public class EventBus { + private final List listeners = new ArrayList<>(); + String lastEvent; + + public void subscribe(WorkflowCommand command) { + listeners.add(command); + } + + public void unsubscribe(WorkflowCommand command) { + listeners.remove(command); + } + + public void publish(String event) { + lastEvent = event; + for (WorkflowCommand listener : listeners) { + listener.run(event, false); + } + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/SmsCommand.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/SmsCommand.java new file mode 100644 index 00000000..c56bad3a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/SmsCommand.java @@ -0,0 +1,9 @@ +package de.monticore.codeAdaption.evaluation.testcase_16_observer_command_combined.concrete; + +public class SmsCommand implements WorkflowCommand { + String phoneNumber; + + @Override + public void run(String event, boolean async) { + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/WorkflowCommand.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/WorkflowCommand.java new file mode 100644 index 00000000..cbbab9d8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_16_observer_command_combined/concrete/WorkflowCommand.java @@ -0,0 +1,5 @@ +package de.monticore.codeAdaption.evaluation.testcase_16_observer_command_combined.concrete; + +public interface WorkflowCommand { + void run(String event, boolean async); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Concrete.cd index 0d27a347..67ab7cf7 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Concrete.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Concrete.cd @@ -1,4 +1,3 @@ -package de.monticore.codeAdaption.evaluation.testcase_2_cd4code; import java.lang.String; import java.util.Date; diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Reference.cd index 84d52cf2..d82008c5 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Reference.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Reference.cd @@ -1,5 +1,5 @@ -package de.monticore.codeAdaption.evaluation.testcase_2_cd4code; import java.lang.String; +import java.util.Date; classdiagram Reference { diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/entity/User.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/entity/User.java index 41eff3c6..fde3af7c 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/entity/User.java +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/entity/User.java @@ -1,4 +1,4 @@ -package de.monticore.codeAdaption.evaluation.testcase_2_cd4code.Concrete; +package Concrete; import de.monticore.codeAdaption.utils.Adapt; diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Concrete.cd new file mode 100644 index 00000000..536414f8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Concrete.cd @@ -0,0 +1,28 @@ +import java.lang.String; +import java.lang.Object; +import java.util.Date; +import java.util.List; + +classdiagram Concrete { + + <> class Person { + <> String name; + <> int age; + <> String email; + <> String phone; + <> List tags; + + <> void sX(Object x); + } + + <> class Task { + <> int id; + <> String title; + <> String description; + <> String status; + <> Date dueDate; + <> String assignee; + + <> void sX(Object x); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Reference.cd new file mode 100644 index 00000000..78994fee --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/Reference.cd @@ -0,0 +1,8 @@ + +classdiagram Reference { + class Builder { + any attribute; + void setAttribute(any attribute); + } +} + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/adapter/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/adapter/Builder.java new file mode 100644 index 00000000..f30cac40 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/adapter/Builder.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.evaluation.testcase_6_builder_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}", genTemplate = "${}Builder") +public class Builder { + private Object attribute; + + @Adapt(ref = {"Builder.attribute"}, template = "set${cap_first}") + public Builder setAttribute(Object attribute) { + this.attribute = attribute; + return this; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/adapter/GenericBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/adapter/GenericBuilder.java new file mode 100644 index 00000000..e69de29b diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/concrete/Person.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/concrete/Person.java new file mode 100644 index 00000000..ea0348e4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/concrete/Person.java @@ -0,0 +1,59 @@ +package de.monticore.codeAdaption.evaluation.testcase_6_builder_pattern; + +import java.util.List; + +/** + * Person domain class with attributes + */ +public class Person { + private String name; + private int age; + private String email; + private String phone; + private List tags; + + public Person() { + } + + public Person(String name, int age, String email, String phone, List tags) { + this.name = name; + this.age = age; + this.email = email; + this.phone = phone; + this.tags = tags; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + public String getEmail() { + return email; + } + + public String getPhone() { + return phone; + } + + public List getTags() { + return tags; + } + + public void sX(Object x) {} + + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + ", age=" + age + + ", email='" + email + '\'' + + ", phone='" + phone + '\'' + + ", tags=" + tags + + '}'; + } +} + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/concrete/Task.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/concrete/Task.java new file mode 100644 index 00000000..b74a4c7b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_6_builder_pattern/concrete/Task.java @@ -0,0 +1,88 @@ +package de.monticore.codeAdaption.evaluation.testcase_6_builder_pattern; + +import java.util.Date; + +/** + * Task domain class with attributes + */ +public class Task { + private int id; + private String title; + private String description; + private String status; + private Date dueDate; + private String assignee; + + public Task() { + } + + public Task(int id, String title, String description, String status, Date dueDate, String assignee) { + this.id = id; + this.title = title; + this.description = description; + this.status = status; + this.dueDate = dueDate; + this.assignee = assignee; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Date getDueDate() { + return dueDate; + } + + public void setDueDate(Date dueDate) { + this.dueDate = dueDate; + } + + public String getAssignee() { + return assignee; + } + + public void setAssignee(String assignee) { + this.assignee = assignee; + } + + @Override + public String toString() { + return "Task{" + + "id=" + id + + ", title='" + title + '\'' + + ", description='" + description + '\'' + + ", status='" + status + '\'' + + ", dueDate=" + dueDate + + ", assignee='" + assignee + '\'' + + '}'; + } +} + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/Concrete.cd new file mode 100644 index 00000000..43da8d35 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/Concrete.cd @@ -0,0 +1,34 @@ +import java.lang.String; +import java.lang.Object; + +classdiagram Concrete { + + <> class Controller { + <> String id; + <> String status; + <> void sX(Object x); + } + + <> interface WorkerInterface { + void work(); + } + + <> class WorkerA implements WorkerInterface { + <> String name; + <> void sX(Object x); + void work(); + } + + <> class WorkerB implements WorkerInterface { + <> String name; + <> void sX(Object x); + void work(); + } +} + + + + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/Reference.cd new file mode 100644 index 00000000..32469955 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/Reference.cd @@ -0,0 +1,25 @@ +import java.util.List; + + +classdiagram Reference { + class Builder { + any attribute; + void setAttribute(any attribute); + } + + class Subject { + List observers; + boolean subscribe(Observer o); + boolean unsubscribe(Observer o); + void notifyAll(); + } + + class Observer { + void update(); + } +} + + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/adapter/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/adapter/Builder.java new file mode 100644 index 00000000..11534ac3 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/adapter/Builder.java @@ -0,0 +1,15 @@ +package de.monticore.codeAdaption.evaluation.testcase_7_controller_worker_observer; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}", genTemplate = "${}Builder") +public class Builder { + private Object attribute; + + @Adapt(ref = {"Builder.attribute"}, template = "set${cap_first}") + public Builder setAttribute(Object attribute) { + this.attribute = attribute; + return this; + } +} + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/adapter/OObserver.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/adapter/OObserver.java new file mode 100644 index 00000000..ae92e393 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/adapter/OObserver.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.evaluation.testcase_7_controller_worker_observer; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Observer"}, template = "${}") +public interface OObserver { + + @Adapt(ref = {"Observer.update"}, template = "update") + void update(); +} + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/adapter/OSubject.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/adapter/OSubject.java new file mode 100644 index 00000000..f7a5839f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/adapter/OSubject.java @@ -0,0 +1,33 @@ +package de.monticore.codeAdaption.evaluation.testcase_7_controller_worker_observer; + +import de.monticore.codeAdaption.utils.Adapt; +import java.util.List; + +@Adapt(ref = {"Subject"}, template = "${}") +public class OSubject { + + @Adapt(ref = {"Subject.observers"}, template = "${}") + private List observers; + + @Adapt(ref = {"Subject.subscribe"}, template = "subscribe") + public boolean subscribe(Observer w) { + // template method body - adapter will replace with concrete implementation + return observers != null && observers.add(w); + } + + @Adapt(ref = {"Subject.unsubscribe"}, template = "unsubscribe") + public boolean unsubscribe(Observer w) { + return observers != null && observers.remove(w); + } + + @Adapt(ref = {"Subject.notifyAll"}, template = "notifyAll") + public void notifyAll() throws Exception { + if (observers == null) return; + for (Observer w : observers) { + w.update(); + } + } +} + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/Controller.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/Controller.java new file mode 100644 index 00000000..93cc8568 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/Controller.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.evaluation.testcase_7_controller_worker_observer; + +/** + * Controller domain class used in the controller/worker observer example + */ +public class Controller { + private String id; + private String status; + + public Controller() { + } + + public Controller(String id, String status) { + this.id = id; + this.status = status; + } + + public String getId() { return id; } + public String getStatus() { return status; } + + public void sX(Object x) { } +} + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/WorkerA.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/WorkerA.java new file mode 100644 index 00000000..83799c54 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/WorkerA.java @@ -0,0 +1,27 @@ +package de.monticore.codeAdaption.evaluation.testcase_7_controller_worker_observer; + +/** + * WorkerA domain class (observer implementation) + */ +public class WorkerA implements WorkerInterface { + private String name; + + public WorkerA() {} + + public WorkerA(String name) { this.name = name; } + + public String getName() { return name; } + + public void update() { /* perform update handling */ } + + @Override + public void work() { /* perform work - adapter may map observer calls to this */ } + + public void sX(Object x) { } + + +} + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/WorkerB.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/WorkerB.java new file mode 100644 index 00000000..c18a8ec6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/WorkerB.java @@ -0,0 +1,26 @@ +package de.monticore.codeAdaption.evaluation.testcase_7_controller_worker_observer; + +/** + * WorkerB domain class (observer implementation) + */ +public class WorkerB implements WorkerInterface { + private String name; + + public WorkerB() {} + + public WorkerB(String name) { this.name = name; } + + public String getName() { return name; } + + + public void update() { /* perform update handling */ } + + @Override + public void work() { /* perform work - adapter may map observer calls to this */ } + + public void sX(Object x) { } +} + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/WorkerInterface.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/WorkerInterface.java new file mode 100644 index 00000000..05f82023 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_7_controller_worker_observer/concrete/WorkerInterface.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.evaluation.testcase_7_controller_worker_observer; + +public interface WorkerInterface { + void work(); +} + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/Concrete.cd new file mode 100644 index 00000000..7a4654b6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/Concrete.cd @@ -0,0 +1,35 @@ +import java.lang.String; +import java.lang.Object; + + +classdiagram Concrete { + + <> class Controller { + <> String id; + <> String status; + <> void sX(Object x); + } + + interface WorkerInterface { + void work(); + } + + <> class WorkerA implements WorkerInterface { + <> String name; + <> void sX(Object x); + void work(); + } + + <> class WorkerB implements WorkerInterface { + <> String name; + <> void sX(Object x); + void work(); + } +} + + + + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/Reference.cd new file mode 100644 index 00000000..311297a5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/Reference.cd @@ -0,0 +1,25 @@ +import java.util.List; + + +classdiagram Reference { + class Builder { + any attribute; + void setAttribute(any attribute); + } + + class Subject { + List observers; + boolean subscribe(Observer o); + boolean unsubscribe(Observer o); + void notifyAll(); + } + + interface Observer { + void update(); + } +} + + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/adapter/Builder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/adapter/Builder.java new file mode 100644 index 00000000..b3978c3c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/adapter/Builder.java @@ -0,0 +1,15 @@ +package de.monticore.codeAdaption.evaluation.testcase_8_controller_worker_observer_reversed; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Builder"}, template = "${}", genTemplate = "${}Builder") +public class Builder { + private Object attribute; + + @Adapt(ref = {"Builder.attribute"}, template = "set${cap_first}") + public Builder setAttribute(Object attribute) { + this.attribute = attribute; + return this; + } +} + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/adapter/OObserver.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/adapter/OObserver.java new file mode 100644 index 00000000..92d8c731 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/adapter/OObserver.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.evaluation.testcase_8_controller_worker_observer_reversed; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Observer"}, template = "${}") +public interface OObserver { + + @Adapt(ref = {"Observer.update"}, template = "update") + void update(); +} + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/adapter/OSubject.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/adapter/OSubject.java new file mode 100644 index 00000000..a6b2cc75 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/adapter/OSubject.java @@ -0,0 +1,33 @@ +package de.monticore.codeAdaption.evaluation.testcase_8_controller_worker_observer_reversed; + +import de.monticore.codeAdaption.utils.Adapt; +import java.util.List; + +@Adapt(ref = {"Subject"}, template = "${}") +public class OSubject { + + @Adapt(ref = {"Subject.observers"}, template = "${}") + private List observers; + + @Adapt(ref = {"Subject.subscribe"}, template = "subscribe") + public boolean subscribe(Observer w) { + // template method body - adapter will replace with concrete implementation + return observers != null && observers.add(w); + } + + @Adapt(ref = {"Subject.unsubscribe"}, template = "unsubscribe") + public boolean unsubscribe(Observer w) { + return observers != null && observers.remove(w); + } + + @Adapt(ref = {"Subject.notifyAll"}, template = "notifyAll") + public void notifyAll() throws Exception { + if (observers == null) return; + for (Observer w : observers) { + w.update(); + } + } +} + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/Controller.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/Controller.java new file mode 100644 index 00000000..72d97d37 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/Controller.java @@ -0,0 +1,25 @@ +package de.monticore.codeAdaption.evaluation.testcase_8_controller_worker_observer_reversed; + +/** + * Controller domain class used in the controller/worker observer example + */ +public class Controller { + private String id; + private String status; + + public Controller() { + } + + public Controller(String id, String status) { + this.id = id; + this.status = status; + } + + public String getId() { return id; } + public String getStatus() { return status; } + + public void sX(Object x) { } +} + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/WorkerA.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/WorkerA.java new file mode 100644 index 00000000..f22fa81e --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/WorkerA.java @@ -0,0 +1,27 @@ +package de.monticore.codeAdaption.evaluation.testcase_8_controller_worker_observer_reversed; + +/** + * WorkerA domain class (observer implementation) + */ +public class WorkerA implements WorkerInterface { + private String name; + + public WorkerA() {} + + public WorkerA(String name) { this.name = name; } + + public String getName() { return name; } + + public void update() { /* perform update handling */ } + + @Override + public void work() { /* perform work - adapter may map observer calls to this */ } + + public void sX(Object x) { } + + +} + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/WorkerB.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/WorkerB.java new file mode 100644 index 00000000..27b17981 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/WorkerB.java @@ -0,0 +1,26 @@ +package de.monticore.codeAdaption.evaluation.testcase_8_controller_worker_observer_reversed; + +/** + * WorkerB domain class (observer implementation) + */ +public class WorkerB implements WorkerInterface { + private String name; + + public WorkerB() {} + + public WorkerB(String name) { this.name = name; } + + public String getName() { return name; } + + + public void update() { /* perform update handling */ } + + @Override + public void work() { /* perform work - adapter may map observer calls to this */ } + + public void sX(Object x) { } +} + + + + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/WorkerInterface.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/WorkerInterface.java new file mode 100644 index 00000000..fbdb9a76 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_8_controller_worker_observer_reversed/concrete/WorkerInterface.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.evaluation.testcase_8_controller_worker_observer_reversed; + +public interface WorkerInterface { + void work(); +} + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/Concrete.cd new file mode 100644 index 00000000..ed343476 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/Concrete.cd @@ -0,0 +1,28 @@ +import java.lang.String; + +classdiagram Concrete { + + <> class PaymentProcessor { + String merchantId; + <> void processPayment(double amount); + } + + <> interface PaymentStrategy { + <> void pay(double amount); + } + + <> class CreditCardStrategy implements PaymentStrategy { + String cardNumber; + <> void pay(double amount); + } + + <> class PayPalStrategy implements PaymentStrategy { + String email; + <> void pay(double amount); + } + + <> class BitcoinStrategy implements PaymentStrategy { + String walletAddress; + <> void pay(double amount); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/Reference.cd new file mode 100644 index 00000000..7d9e74f8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/Reference.cd @@ -0,0 +1,20 @@ + +classdiagram Reference { + class Context { + Strategy strategy; + void setStrategy(Strategy strategy); + void execute(any attribute); + } + + interface Strategy { + void execute(any attribute); + } + + class ConcreteStrategyA implements Strategy { + void execute(any attribute); + } + + class ConcreteStrategyB implements Strategy { + void execute(any attribute); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/adapter/Context.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/adapter/Context.java new file mode 100644 index 00000000..c735fa80 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/adapter/Context.java @@ -0,0 +1,18 @@ +package de.monticore.codeAdaption.evaluation.testcase_9_strategy_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Context"}, template = "${}") +public class Context { + private Strategy strategy; + + @Adapt(ref = {"Context.strategy"}, template = "set${cap_first}") + public void setStrategy(Strategy strategy) { + this.strategy = strategy; + } + + @Adapt(ref = {"Context.execute"}, template = "${}") + public void execute() { + strategy.execute(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/adapter/Strategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/adapter/Strategy.java new file mode 100644 index 00000000..f649b259 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/adapter/Strategy.java @@ -0,0 +1,10 @@ +package de.monticore.codeAdaption.evaluation.testcase_9_strategy_pattern; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ref = {"Strategy"}, template = "${}") +public interface Strategy { + + @Adapt(ref = {"Strategy.execute"}, template = "${}") + void execute(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/BitcoinStrategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/BitcoinStrategy.java new file mode 100644 index 00000000..43d7dbc5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/BitcoinStrategy.java @@ -0,0 +1,21 @@ +package de.monticore.codeAdaption.evaluation.testcase_9_strategy_pattern; + +/** + * BitcoinStrategy concrete implementation of PaymentStrategy + */ +public class BitcoinStrategy implements PaymentStrategy { + private String walletAddress; + + public BitcoinStrategy() { + } + + public BitcoinStrategy(String walletAddress) { + this.walletAddress = walletAddress; + } + + public String getWalletAddress() { return walletAddress; } + + public void pay(double amount) { + System.out.println("Paid $" + amount + " using Bitcoin"); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/CreditCardStrategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/CreditCardStrategy.java new file mode 100644 index 00000000..e5f20b20 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/CreditCardStrategy.java @@ -0,0 +1,21 @@ +package de.monticore.codeAdaption.evaluation.testcase_9_strategy_pattern; + +/** + * CreditCardStrategy concrete implementation of PaymentStrategy + */ +public class CreditCardStrategy implements PaymentStrategy { + private String cardNumber; + + public CreditCardStrategy() { + } + + public CreditCardStrategy(String cardNumber) { + this.cardNumber = cardNumber; + } + + public String getCardNumber() { return cardNumber; } + + public void pay(double amount) { + System.out.println("Paid $" + amount + " using Credit Card"); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/PayPalStrategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/PayPalStrategy.java new file mode 100644 index 00000000..79620421 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/PayPalStrategy.java @@ -0,0 +1,21 @@ +package de.monticore.codeAdaption.evaluation.testcase_9_strategy_pattern; + +/** + * PayPalStrategy concrete implementation of PaymentStrategy + */ +public class PayPalStrategy implements PaymentStrategy { + private String email; + + public PayPalStrategy() { + } + + public PayPalStrategy(String email) { + this.email = email; + } + + public String getEmail() { return email; } + + public void pay(double amount) { + System.out.println("Paid $" + amount + " using PayPal"); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/PaymentProcessor.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/PaymentProcessor.java new file mode 100644 index 00000000..64866669 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/PaymentProcessor.java @@ -0,0 +1,21 @@ +package de.monticore.codeAdaption.evaluation.testcase_9_strategy_pattern; + +/** + * PaymentProcessor domain class + */ +public class PaymentProcessor { + private String merchantId; + + public PaymentProcessor() { + } + + public PaymentProcessor(String merchantId) { + this.merchantId = merchantId; + } + + public String getMerchantId() { return merchantId; } + + public void processPayment(double amount) { + System.out.println("Processing payment of $" + amount); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/PaymentStrategy.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/PaymentStrategy.java new file mode 100644 index 00000000..9fa45c9b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_9_strategy_pattern/concrete/PaymentStrategy.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.evaluation.testcase_9_strategy_pattern; + +/** + * PaymentStrategy interface + */ +public interface PaymentStrategy { + void pay(double amount); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/Validator.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/Validator.cd index 5ebb7a38..251bed16 100644 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/Validator.cd +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/Validator.cd @@ -1,3 +1,4 @@ +import java.lang.String; classdiagram Validator{ public class Entity { String id ; diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/InvalidTemplate.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/InvalidTemplate.java deleted file mode 100644 index b3ab1061..00000000 --- a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/InvalidTemplate.java +++ /dev/null @@ -1,13 +0,0 @@ -import de.monticore.codeAdaption.utils.Adapt; - -@Adapt(template = "${}",ref = "Entity") -public class InvalidTemplate { - @Adapt(template = "${}",ref = "Entity") - public String someAttribut ; - - @Adapt(template = "${}",ref = "Entity") - public void someMethod(@Adapt(template = "${}",ref = "Entity")String args) { - @Adapt(template = "${}",ref = "Entity") - String someLocalvar ; - } -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 6a86540a..073d94ee 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,6 +16,14 @@ pluginManagement { } dependencyResolutionManagement { + repositories { + mavenLocal() + maven { + credentials.username mavenUser + credentials.password mavenPassword + url repo + } + } versionCatalogs { create("corpusLibs") { from(files("./gradle/corpus.versions.toml"))