diff --git a/cpp/autosar/src/rules/M14-6-1/NameInDependentBase.qll b/cpp/autosar/src/rules/M14-6-1/NameInDependentBase.qll index 93c99c3d76..b3d12c044b 100644 --- a/cpp/autosar/src/rules/M14-6-1/NameInDependentBase.qll +++ b/cpp/autosar/src/rules/M14-6-1/NameInDependentBase.qll @@ -2,49 +2,112 @@ import cpp import codingstandards.cpp.autosar /** - * Just the reverse of `Class.getABaseClass()` + * Gets a dependent base type of the given template class. + * + * This returns the `TemplateClass` for the base type, rather than the `ClassTemplateInstantiation`, + * as the instantiation does not appear to include any member declarations. */ -Class getParent(Class child) { child.getABaseClass() = result } +TemplateClass getADependentBaseType(TemplateClass t) { + exists(ClassTemplateInstantiation baseType | + baseType = t.getABaseClass() and + // Base type depends on at least one of the template parameters of class t + baseType.getATemplateArgument() = t.getATemplateArgument() and + // Return the template itself + result = baseType.getTemplate() + ) +} /** - * There is a `MemberFunction` in parent class with same name - * as a `FunctionCall` that exists in a child `MemberFunction` + * Helper predicate that ensures we do not join on function pairs by name early on, as that creates + * a large dataset on big databases with lots of name duplication. */ -FunctionCall parentMemberFunctionCall(Class child, Class parent) { - exists(MemberFunction parentFunction, Function other | - not other = parentFunction and - parent.getAMember() = parentFunction and - other.getName() = parentFunction.getName() and - result = other.getACallToThisFunction() and - result.getEnclosingFunction() = child.getAMemberFunction() +pragma[nomagic] +private FunctionCall helper_functioncall( + TemplateClass t, TemplateClass dependentBaseType, Function target, string name +) { + dependentBaseType = getADependentBaseType(t) and + // The target of the call is not declared in the dependent base type + not target.getDeclaringType() = dependentBaseType and + result = target.getACallToThisFunction() and + result.getEnclosingFunction() = t.getAMemberFunction() and + name = target.getName() +} + +/** + * Gets a function call in `TemplateClass` `t` where the target function name exists in a dependent + * base type and the call is to a function that is not declared in the dependent base type. + */ +FunctionCall getConfusingFunctionCall( + TemplateClass t, string name, Function target, MemberFunction dependentTypeFunction +) { + exists(TemplateClass dependentBaseType | + result = helper_functioncall(t, dependentBaseType, target, name) and + // The dependentTypeFunction is declared on the dependent base type + dependentBaseType.getAMember() = dependentTypeFunction and + // And has the same name as the target of the function call in the child + name = dependentTypeFunction.getName() ) } /** - * There is a `MemberFunction` in parent class with same name - * as a `FunctionAccess` that exists in a child `MemberFunction` + * Helper predicate that ensures we do not join on function pairs by name early on, as that creates + * a large dataset on big databases with lots of name duplication. + */ +pragma[nomagic] +private FunctionAccess helper_functionaccess( + TemplateClass t, TemplateClass dependentBaseType, Function target, string name +) { + dependentBaseType = getADependentBaseType(t) and + // The target of the access is not declared in the dependent base type + not target.getDeclaringType() = dependentBaseType and + result = target.getAnAccess() and + result.getEnclosingFunction() = t.getAMemberFunction() and + name = target.getName() +} + +/** + * Gets a function access in `TemplateClass` `t` where the target function name exists in a dependent + * base type and the access is to a function declared outside the dependent base type. */ -FunctionAccess parentMemberFunctionAccess(Class child, Class parent) { - exists(MemberFunction parentFunction, Function other | - not other = parentFunction and - parent.getAMember() = parentFunction and - other.getName() = parentFunction.getName() and - result = other.getAnAccess() and - result.getEnclosingFunction() = child.getAMemberFunction() +FunctionAccess getConfusingFunctionAccess( + TemplateClass t, string name, Function target, MemberFunction dependentTypeFunction +) { + exists(TemplateClass dependentBaseType | + result = helper_functionaccess(t, dependentBaseType, target, name) and + dependentBaseType.getAMember() = dependentTypeFunction and + name = dependentTypeFunction.getName() ) } /** - * There is a `MemberVariable` in parent class with same name - * as a `VariableAccess` that exists in a child `MemberFunction` + * Helper predicate that ensures we do not join on variable pairs by name early on, as that creates + * a large dataset on big databases with lots of name duplication. + */ +pragma[nomagic] +private VariableAccess helper_memberaccess( + TemplateClass t, TemplateClass dependentBaseType, Variable target, string name +) { + dependentBaseType = getADependentBaseType(t) and + // The target of the access is not declared in the dependent base type + not target.getDeclaringType() = dependentBaseType and + result = target.getAnAccess() and + result.getEnclosingFunction() = t.getAMemberFunction() and + name = target.getName() and + // The target is not a local variable, which isn't subject to confusion + not target instanceof LocalScopeVariable +} + +/** + * Gets a memmber access in `TemplateClass` `t` where the target member name exists in a dependent + * base type and the access is to a variable declared outside the dependent base type. */ -Access parentMemberAccess(Class child, Class parent) { - exists(MemberVariable parentMember, Variable other | - not other = parentMember and - parent.getAMemberVariable() = parentMember and - other.getName() = parentMember.getName() and - result = other.getAnAccess() and - result.getEnclosingFunction() = child.getAMemberFunction() +VariableAccess getConfusingMemberVariableAccess( + TemplateClass t, string name, Variable target, MemberVariable dependentTypeMemberVariable +) { + exists(TemplateClass dependentBaseType | + result = helper_memberaccess(t, dependentBaseType, target, name) and + dependentBaseType.getAMemberVariable() = dependentTypeMemberVariable and + name = dependentTypeMemberVariable.getName() ) } diff --git a/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.ql b/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.ql index 7d23ddb949..2736d39290 100644 --- a/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.ql +++ b/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.ql @@ -18,24 +18,25 @@ import cpp import codingstandards.cpp.autosar import NameInDependentBase -from Class c, Class p, NameQualifiableElement fn +from + TemplateClass c, NameQualifiableElement fn, string targetName, Element actualTarget, + Element dependentTypeMemberWithSameName where not isExcluded(fn, TemplatesPackage::nameNotReferredUsingAQualifiedIdOrThisQuery()) and not isCustomExcluded(fn) and - p = getParent(c) and missingNameQualifier(fn) and ( - fn instanceof FunctionAccess and - fn = parentMemberFunctionAccess(c, p) + fn = getConfusingFunctionAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) or - fn instanceof FunctionCall and - fn = parentMemberFunctionCall(c, p) and + fn = getConfusingFunctionCall(c, targetName, actualTarget, dependentTypeMemberWithSameName) and not exists(Expr e | e = fn.(FunctionCall).getQualifier()) or - fn instanceof VariableAccess and - not fn.(VariableAccess).getTarget() instanceof Parameter and - fn = parentMemberAccess(c, p) and + fn = + getConfusingMemberVariableAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) and not exists(Expr e | e = fn.(VariableAccess).getQualifier()) ) and not fn.isAffectedByMacro() -select fn, "Use of identifier that also exists in a base class that is not fully qualified." +select fn, + "Use of unqualified identifier " + targetName + + " targets $@ but a member with the name also exists $@.", actualTarget, targetName, + dependentTypeMemberWithSameName, "in the dependent base class" diff --git a/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.ql b/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.ql index e231967ad1..401edf3b61 100644 --- a/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.ql +++ b/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.ql @@ -18,23 +18,25 @@ import cpp import codingstandards.cpp.autosar import NameInDependentBase -from Class c, Class p, NameQualifiableElement fn +from + TemplateClass c, NameQualifiableElement fn, string targetName, Element actualTarget, + Element dependentTypeMemberWithSameName where not isExcluded(fn, TemplatesPackage::nameNotReferredUsingAQualifiedIdOrThisAuditQuery()) and not isCustomExcluded(fn) and - p = getParent(c) and missingNameQualifier(fn) and ( - fn instanceof FunctionAccess and - fn = parentMemberFunctionAccess(c, p) + fn = getConfusingFunctionAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) or - fn instanceof FunctionCall and - fn = parentMemberFunctionCall(c, p) and + fn = getConfusingFunctionCall(c, targetName, actualTarget, dependentTypeMemberWithSameName) and not exists(Expr e | e = fn.(FunctionCall).getQualifier()) or - fn instanceof VariableAccess and not fn.(VariableAccess).getTarget() instanceof Parameter and - fn = parentMemberAccess(c, p) and + fn = + getConfusingMemberVariableAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) and not exists(Expr e | e = fn.(VariableAccess).getQualifier()) ) -select fn, "Use of identifier that also exists in a base class that is not fully qualified." +select fn, + "Use of unqualified identifier " + targetName + + " targets $@ but a member with the name also exists $@.", actualTarget, targetName, + dependentTypeMemberWithSameName, "in the dependent base class" diff --git a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.expected b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.expected index c117f6d9ed..1ea2cb3ab5 100644 --- a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.expected +++ b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.expected @@ -1,3 +1,3 @@ -| test.cpp:16:5:16:5 | m | Use of identifier that also exists in a base class that is not fully qualified. | -| test.cpp:17:5:17:5 | call to g | Use of identifier that also exists in a base class that is not fully qualified. | -| test.cpp:19:20:19:20 | g | Use of identifier that also exists in a base class that is not fully qualified. | +| test.cpp:16:5:16:5 | m | Use of unqualified identifier m targets $@ but a member with the name also exists $@. | test.cpp:4:5:4:5 | m | m | test.cpp:10:7:10:7 | m | in the dependent base class | +| test.cpp:17:5:17:5 | call to g | Use of unqualified identifier g targets $@ but a member with the name also exists $@. | test.cpp:2:6:2:6 | g | g | test.cpp:9:8:9:8 | g | in the dependent base class | +| test.cpp:19:20:19:20 | g | Use of unqualified identifier g targets $@ but a member with the name also exists $@. | test.cpp:2:6:2:6 | g | g | test.cpp:9:8:9:8 | g | in the dependent base class | diff --git a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.expected b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.expected index c117f6d9ed..1ea2cb3ab5 100644 --- a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.expected +++ b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.expected @@ -1,3 +1,3 @@ -| test.cpp:16:5:16:5 | m | Use of identifier that also exists in a base class that is not fully qualified. | -| test.cpp:17:5:17:5 | call to g | Use of identifier that also exists in a base class that is not fully qualified. | -| test.cpp:19:20:19:20 | g | Use of identifier that also exists in a base class that is not fully qualified. | +| test.cpp:16:5:16:5 | m | Use of unqualified identifier m targets $@ but a member with the name also exists $@. | test.cpp:4:5:4:5 | m | m | test.cpp:10:7:10:7 | m | in the dependent base class | +| test.cpp:17:5:17:5 | call to g | Use of unqualified identifier g targets $@ but a member with the name also exists $@. | test.cpp:2:6:2:6 | g | g | test.cpp:9:8:9:8 | g | in the dependent base class | +| test.cpp:19:20:19:20 | g | Use of unqualified identifier g targets $@ but a member with the name also exists $@. | test.cpp:2:6:2:6 | g | g | test.cpp:9:8:9:8 | g | in the dependent base class | diff --git a/cpp/autosar/test/rules/M14-6-1/test.cpp b/cpp/autosar/test/rules/M14-6-1/test.cpp index 7358a5e5e0..b16e6b40dc 100644 --- a/cpp/autosar/test/rules/M14-6-1/test.cpp +++ b/cpp/autosar/test/rules/M14-6-1/test.cpp @@ -29,10 +29,59 @@ template class A : B { typename B::TYPE t2 = 0; // COMPLIANT g1(); // COMPLIANT, identifier not found in B } + void m3(int m) { + m = 0; // COMPLIANT, hides member + } + void m4() { + int m = 0; + m = 0; // COMPLIANT, hides member + } }; void f() { A a; a.m1(); a.m2(); + a.m3(1); + a.m4(); +} + +class D { +public: + typedef int TYPE; + void g(); + void g(int x); + static void sg(); + static void sg(int x); + int m; +}; + +class C : D { +public: + void m1() { + m = 0; // COMPLIANT - does not apply to non-class templates + g(); // COMPLIANT - does not apply to non-class templates + sg(); // COMPLIANT - does not apply to non-class templates + TYPE t1 = 0; // COMPLIANT - does not apply to non-class templates + // void (*p)() = &g; // NON_COMPILABLE - not valid to take address of member + // function without qualifier + } +}; + +template class E : D { +public: + void m1() { + m = 0; // COMPLIANT - does not apply to non dependent base types + g(); // COMPLIANT - does not apply to non dependent base types + TYPE t1 = 0; // COMPLIANT - does not apply to non dependent base types + // void (*p)() = &g; // NON_COMPILABLE - not valid to take address of member + // function without qualifier + } +}; + +void f2() { + C c; + c.m1(); + E e; + e.m1(); } \ No newline at end of file