Files
codeql/cpp/ql/src/Best Practices/RuleOfTwo.ql
Anders Schack-Mulligen 96e4a57edd C++: Autoformat.
2020-01-29 13:11:50 +01:00

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