mirror of
https://github.com/github/codeql.git
synced 2026-02-09 11:41:06 +01:00
67 lines
2.7 KiB
Plaintext
67 lines
2.7 KiB
Plaintext
/**
|
|
* @name Inconsistent definition of copy constructor and assignment ('Rule of Two')
|
|
* @description Classes that have an explicit copy constructor or copy
|
|
* assignment operator may behave inconsistently if they do
|
|
* not have both.
|
|
* @kind problem
|
|
* @problem.severity warning
|
|
* @precision high
|
|
* @id cpp/rule-of-two
|
|
* @tags reliability
|
|
* readability
|
|
* language-features
|
|
*/
|
|
|
|
import cpp
|
|
|
|
// This query enforces the Rule of Two, which is a conservative variation of
|
|
// the more well-known Rule of Three.
|
|
//
|
|
// The Rule of Two is usually phrased informally, ignoring the distinction
|
|
// between whether a member is missing because it's auto-generated (missing
|
|
// from the source) or missing because it can't be called (missing from the
|
|
// generated code).
|
|
//
|
|
// This query checks if one member is explicitly defined while the other is
|
|
// auto-generated. This can lead to memory safety issues. It's a separate issue
|
|
// whether one is callable while the other is not callable; that is an API
|
|
// design question and carries has no safety risk.
|
|
predicate generatedCopyAssignment(CopyConstructor cc, string msg) {
|
|
cc.getDeclaringType().hasImplicitCopyAssignmentOperator() and
|
|
msg =
|
|
"No matching copy assignment operator in class " + cc.getDeclaringType().getName() +
|
|
". It is good practice to match a copy constructor with a " + "copy assignment operator."
|
|
}
|
|
|
|
predicate generatedCopyConstructor(CopyAssignmentOperator ca, string msg) {
|
|
ca.getDeclaringType().hasImplicitCopyConstructor() and
|
|
msg =
|
|
"No matching copy constructor in class " + ca.getDeclaringType().getName() +
|
|
". It is good practice to match a copy assignment operator with a " + "copy constructor."
|
|
}
|
|
|
|
from MemberFunction f, string msg
|
|
where
|
|
(
|
|
generatedCopyAssignment(f, msg) or
|
|
generatedCopyConstructor(f, msg)
|
|
) and
|
|
// Ignore template instantiations to prevent an explosion of alerts
|
|
not f.getDeclaringType().isConstructedFrom(_) and
|
|
// Ignore private members since a private constructor or assignment operator
|
|
// is a common idiom that simulates suppressing the default-generated
|
|
// members. It would be better to use C++11's "delete" facility or use
|
|
// appropriate Boost helper classes, but it is too common to report as a
|
|
// violation.
|
|
not f.isPrivate() and
|
|
// If it is truly user-defined then it must have a body. This leaves out
|
|
// C++11 members that use `= delete` or `= default`.
|
|
exists(f.getBlock()) and
|
|
// In rare cases, the extractor pretends that an auto-generated copy
|
|
// constructor has a block that is one character long and is located on top
|
|
// of the first character of the class name. Checking for
|
|
// `isCompilerGenerated` will remove those results.
|
|
not f.isCompilerGenerated() and
|
|
not f.isDeleted()
|
|
select f, msg
|