use of org.eclipse.n4js.ts.types.MemberAccessModifier in project n4js by eclipse.
the class N4JSMemberRedefinitionValidator method constraints_65_overrideCompatible.
/**
* Constraints 65 (Override Compatible) and relation overrideCompatible.
*
* @param m
* the overriding member
* @param s
* the overridden or implemented member
* @param consumptionConflict
* check override or implementation override, the latter usually stems from a consumption conflict (so
* that s did not get consumed in the first place)
* @param mm
* member matrix, only to improve error message
* @return true if m is override compatible to s. Note that false does not necessarily means that an error occurred,
* since e.g., a getter does not effect a setter
*/
private OverrideCompatibilityResult constraints_65_overrideCompatible(RedefinitionType redefinitionType, TMember m, TMember s, boolean consumptionConflict, MemberMatrix mm) {
// 1. name and static modifier are always equal here, so we do not have to check that again
// 2. meta type
boolean metaTypeCompatible = MemberRedefinitionUtils.isMetaTypeCompatible(m, s);
if (!metaTypeCompatible) {
if (!consumptionConflict) {
// avoid consequential errors
messageOverrideMetaTypeIncompatible(redefinitionType, m, s, mm);
}
return OverrideCompatibilityResult.ERROR;
}
// 3. s not final
if (s.isFinal()) {
if (!consumptionConflict) {
// avoid consequential errors
messageOverrideFinal(redefinitionType, m, s);
}
return OverrideCompatibilityResult.ERROR;
}
final boolean sIsField = s instanceof TField;
final boolean sIsSetter = s instanceof TSetter;
final boolean mIsField = m instanceof TField;
// 4. s not const
if (sIsField) {
// const only defined on TField & TStructuralField
TField sF = (TField) s;
if (sF.isConst()) {
// By GHOLD-186 const redefinition is allowed for const fields
if (!((mIsField) && ((TField) m).isConst())) {
if (!consumptionConflict) {
// avoid consequential errors
messageOverrideConst(redefinitionType, m, sF);
}
return OverrideCompatibilityResult.ERROR;
}
}
}
// 5. must not override non-final/non-const field or setter with a @Final/const field
if (sIsField || sIsSetter) {
if (!s.isFinal() && !s.isConst()) {
if (mIsField && (m.isFinal() || m.isConst())) {
if (!consumptionConflict) {
// avoid consequential errors
messageOverrideWithFinalOrConstField(redefinitionType, m, s);
}
return OverrideCompatibilityResult.ERROR;
}
}
}
// 6. abstract
if (m.isAbstract() && !s.isAbstract()) {
if (!consumptionConflict) {
// avoid consequential errors
messageOverrideAbstract(redefinitionType, m, s);
}
return OverrideCompatibilityResult.ERROR;
}
// 7. type compatible
if (!m.isSetter() && !s.isSetter()) {
// in Method (including constructor), Getter, Field
Result<Boolean> result = isSubTypeResult(m, s);
if (result.failed()) {
if (!consumptionConflict) {
// avoid consequential errors
messageOverrideMemberTypeConflict(redefinitionType, m, s, result, mm);
}
return OverrideCompatibilityResult.ERROR;
}
}
boolean sIsConst = false;
if (sIsField) {
sIsConst = ((TField) s).isConst();
}
if ((m.isSetter() || m.isField()) && !s.isGetter() && !sIsConst) {
Result<Boolean> result = isSubTypeResult(s, m);
if (result.failed()) {
if (!consumptionConflict) {
// avoid consequential errors
messageOverrideMemberTypeConflict(redefinitionType, m, s, result, mm);
}
return OverrideCompatibilityResult.ERROR;
}
}
// 8.1 accessibility must not be reduced
if (AccessModifiers.checkedLess(m, s)) {
// fix modifiers in order to avoid strange behavior
if (!consumptionConflict) {
// avoid consequential errors
messageOverrideAccessibilityReduced(redefinitionType, m, s);
}
return OverrideCompatibilityResult.ERROR;
}
// 8.2 special accessibility handling of public@Internal and protected as they reduce each other
MemberAccessModifier fixedLeft = AccessModifiers.fixed(m);
MemberAccessModifier fixedRight = AccessModifiers.fixed(s);
if ((fixedLeft == MemberAccessModifier.PROTECTED && fixedRight == MemberAccessModifier.PUBLIC_INTERNAL) || (fixedLeft == MemberAccessModifier.PUBLIC_INTERNAL && fixedRight == MemberAccessModifier.PROTECTED)) {
messageOverrideAccessibilityReduced(redefinitionType, m, s);
return OverrideCompatibilityResult.ERROR;
}
return OverrideCompatibilityResult.COMPATIBLE;
}
use of org.eclipse.n4js.ts.types.MemberAccessModifier in project n4js by eclipse.
the class ProjectCompareHelper method internalCompareApiImpl.
private ProjectCompareResult internalCompareApiImpl(ProjectComparisonEntry entry, int implIdx) {
if (!entry.isElementEntry())
// not an entry for an EObject element -> never report differences
return ProjectCompareResult.equal();
final int implCount = entry.getImplCount();
if (implIdx < 0 || implIdx >= implCount)
// implementation index out of range -> never report differences
return ProjectCompareResult.equal();
// compare implementation to API
final EObject api = entry.getElementAPI();
final EObject impl = entry.getElementImpl()[implIdx];
// special case: no API
if (api == null) {
if (impl != null)
return ProjectCompareResult.compliant();
else
return ProjectCompareResult.equal();
}
// special case: no impl
if (impl == null) {
// note: we know api!=null because of above check
return ProjectCompareResult.error("missing implementation");
}
// accessibility-based compare:
if (api instanceof TMember && impl instanceof TMember) {
// order important: check for member before type!
if (AccessModifiers.less((TMember) impl, (TMember) api))
return ProjectCompareResult.error("reduced visibility");
} else if (api instanceof Type && impl instanceof Type) {
final MemberAccessModifier apiAcc = AccessModifiers.toMemberModifier((Type) api);
final MemberAccessModifier implAcc = AccessModifiers.toMemberModifier((Type) impl);
if (AccessModifiers.less(implAcc, apiAcc))
return ProjectCompareResult.error("reduced visibility");
}
ImplToApiReplacementProvider typeReplacementProvider = new ImplToApiReplacementProvider(entry.getRoot());
// subtype-based compare:
if (api instanceof TMember && impl instanceof TMember) {
final TMember apiMember = (TMember) api;
final TMember implMember = (TMember) impl;
if (apiMember instanceof TField) {
boolean bAPIProvidesInitializer = PROVIDES_INITIALZER.hasAnnotation(apiMember);
if (bAPIProvidesInitializer && !hasInitializer(impl)) {
if (bAPIProvidesInitializer) {
return ProjectCompareResult.error("no initializer in implementation but @" + PROVIDES_INITIALZER.name + " in API");
} else {
return ProjectCompareResult.error("initializer in implementation but no @" + PROVIDES_INITIALZER.name + " in API)");
}
}
} else {
// Method or accessor
boolean bAPIProvidesDefImpl = PROVIDES_DEFAULT_IMPLEMENTATION.hasAnnotation(apiMember);
if ((bAPIProvidesDefImpl != hasBody(impl)) && apiMember.eContainer() instanceof TInterface) {
if (bAPIProvidesDefImpl) {
return ProjectCompareResult.error("no body in implementation but @" + PROVIDES_DEFAULT_IMPLEMENTATION.name + " in API");
} else {
return ProjectCompareResult.error("body in implementation but no @" + PROVIDES_DEFAULT_IMPLEMENTATION.name + " in API");
}
}
}
final TypeRef context = TypeUtils.createTypeRef((Type) api.eContainer());
final TypeRef typeApi = typeSystem.tau(apiMember, context);
final TypeRef typeImpl = typeSystem.tau(implMember, context);
final RuleEnvironment G = RuleEnvironmentExtensions.newRuleEnvironment(api);
RuleEnvironmentExtensions.setTypeReplacement(G, typeReplacementProvider);
final Result<Boolean> implSubtypeApi = typeSystem.subtype(G, typeImpl, typeApi);
final Result<Boolean> apiSubtypeImpl = typeSystem.subtype(G, typeApi, typeImpl);
final boolean isImplSubtypeApi = !implSubtypeApi.failed();
final boolean isApiSubtypeImpl = !apiSubtypeImpl.failed();
final boolean isEqualType = isImplSubtypeApi && isApiSubtypeImpl;
if (!isEqualType) {
if (isImplSubtypeApi)
// not equal but at least compliant
return ProjectCompareResult.compliant();
else {
final String msg = implSubtypeApi.getRuleFailedException().getLocalizedMessage();
// not even compliant
return ProjectCompareResult.error(msg);
}
}
if (isSpecialCaseOfHiddenMethodDiff(api, impl)) {
// not equal but at least compliant
return ProjectCompareResult.compliant();
}
// all fine
return ProjectCompareResult.equal();
}
// classifier compare
if (api instanceof TClassifier && impl instanceof TClassifier) {
TClassifier apiClassifier = (TClassifier) api;
TClassifier implClassifier = (TClassifier) impl;
EList<TypeVariable> apiTypeVars = apiClassifier.getTypeVars();
EList<TypeVariable> implTypeVars = implClassifier.getTypeVars();
// check for number of type variables
if (apiTypeVars.size() != implTypeVars.size()) {
return ProjectCompareResult.error("the number of type variables doesn't match");
}
final RuleEnvironment ruleEnvironment = RuleEnvironmentExtensions.newRuleEnvironment(api);
RuleEnvironmentExtensions.setTypeReplacement(ruleEnvironment, typeReplacementProvider);
// check for upper bound compatibility
for (int i = 0; i < apiTypeVars.size(); i++) {
TypeVariable apiTypeVar = apiTypeVars.get(i);
TypeVariable implTypeVar = implTypeVars.get(i);
TypeRef apiDeclaredUpperBound = apiTypeVar.getDeclaredUpperBound();
TypeRef implDeclaredUpperBound = implTypeVar.getDeclaredUpperBound();
if ((apiDeclaredUpperBound != null) != (implDeclaredUpperBound != null) || (apiDeclaredUpperBound != null && implDeclaredUpperBound != null && !typeSystem.equaltypeSucceeded(ruleEnvironment, apiDeclaredUpperBound, implDeclaredUpperBound))) {
return ProjectCompareResult.error(String.format("the upper bound of type variable %s isn't compatible with the API", implTypeVar.getName()));
}
}
return ProjectCompareResult.equal();
}
// text-based compare:
// always compare with API
final String textApi = entry.getTextAPI();
final String textImpl = entry.getTextImpl(implIdx);
final boolean isEqual = textApi != null ? textApi.equals(textImpl) : textImpl == null;
if (!isEqual)
return ProjectCompareResult.error(textImpl + " is not equal to " + textApi);
return ProjectCompareResult.equal();
}
use of org.eclipse.n4js.ts.types.MemberAccessModifier in project n4js by eclipse.
the class AccessModifiers method fixed.
/**
* Returns either the declared access modifier, or a correct fixed version. E.g., members of interfaces must never
* be declared private, thus such a modifier is corrected to project. Note that
* {@link TMemberWithAccessModifier#getMemberAccessModifier()} may calculate the modifier if it is undefined, but
* does not "fix" a wrongly declared modifier.
*/
public static MemberAccessModifier fixed(TMember m) {
MemberAccessModifier modifier = m.getMemberAccessModifier();
Type containingType = m.getContainingType();
if (containingType instanceof TInterface) {
// correspongingMAM will be one of {PRIVATE PROJECT PUBLIC_INTERNAL PUBLIC} - with PROJECT as default.
MemberAccessModifier correspondingTypesMAM = toMemberModifier(containingType);
if (correspondingTypesMAM == MemberAccessModifier.PRIVATE && containingType instanceof TInterface) {
correspondingTypesMAM = MemberAccessModifier.PROJECT;
}
}
return modifier;
}
use of org.eclipse.n4js.ts.types.MemberAccessModifier in project n4js by eclipse.
the class MemberVisibilityChecker method isVisible.
/**
* Returns the MemberVisibility of the <i>member</i> of the <i>receiverType</> in the given <i>context</i>
*/
private MemberVisibility isVisible(TModule contextModule, Type contextType, Type declaredReceiverType, TMember member, boolean supercall) {
int startIndex = member.getMemberAccessModifier().getValue();
boolean visibility = false;
String firstVisible = "PUBLIC";
for (int i = startIndex; i < MemberAccessModifier.values().length; i++) {
boolean visibilityForModifier = false;
MemberAccessModifier modifier = MemberAccessModifier.get(i);
switch(modifier) {
case PRIVATE:
visibilityForModifier = isModuleVisible(contextModule, member);
break;
case PROJECT:
visibilityForModifier = isProjectVisible(contextModule, member);
break;
case PROTECTED_INTERNAL:
visibilityForModifier = isProtectedInternalVisible(contextType, contextModule, declaredReceiverType, member, supercall);
break;
case PROTECTED:
visibilityForModifier = isProtectedVisible(contextType, contextModule, declaredReceiverType, member, supercall);
break;
case PUBLIC_INTERNAL:
visibilityForModifier = isPublicInternalVisible(contextType, contextModule, declaredReceiverType, member);
break;
case PUBLIC:
visibilityForModifier = true;
break;
default:
break;
}
// First modifier = element modifier
if (i - startIndex < 1) {
visibility = visibilityForModifier;
}
// First visible modifier = suggested element modifier
if (visibilityForModifier) {
firstVisible = modifier.getName();
break;
}
}
return new MemberVisibility(visibility, firstVisible);
}
use of org.eclipse.n4js.ts.types.MemberAccessModifier in project n4js by eclipse.
the class TMethodImpl method getMemberAccessModifier.
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public MemberAccessModifier getMemberAccessModifier() {
MemberAccessModifier _declaredMemberAccessModifier = this.getDeclaredMemberAccessModifier();
boolean _tripleEquals = (_declaredMemberAccessModifier == MemberAccessModifier.UNDEFINED);
if (_tripleEquals) {
final EObject parent = this.eContainer();
if ((parent instanceof TInterface)) {
final MemberAccessModifier modifierDerivedFromType = AccessModifiers.toMemberModifier(((Type) parent).getTypeAccessModifier());
if ((modifierDerivedFromType != MemberAccessModifier.PRIVATE)) {
return modifierDerivedFromType;
}
}
return MemberAccessModifier.PROJECT;
}
return this.getDeclaredMemberAccessModifier();
}
Aggregations