Skip to content

M14-6-1: Address performance problems and restrict scope #205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 92 additions & 29 deletions cpp/autosar/src/rules/M14-6-1/NameInDependentBase.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Original file line number Diff line number Diff line change
@@ -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 |
Original file line number Diff line number Diff line change
@@ -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 |
49 changes: 49 additions & 0 deletions cpp/autosar/test/rules/M14-6-1/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,59 @@ template <typename T> class A : B<T> {
typename B<T>::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<int> 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 <typename T> 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<int> e;
e.m1();
}