| 2184 | //--------------------------------------------------------------------------- |
| 2185 | |
| 2186 | void CheckClassImpl::checkConst() |
| 2187 | { |
| 2188 | if (!mSettings.severity.isEnabled(Severity::style) && |
| 2189 | !mSettings.isPremiumEnabled("functionConst") && |
| 2190 | !mSettings.isPremiumEnabled("functionStatic")) |
| 2191 | return; |
| 2192 | |
| 2193 | logChecker("CheckClass::checkConst"); // style,inconclusive |
| 2194 | |
| 2195 | for (const Scope * scope : mSymbolDatabase->classAndStructScopes) { |
| 2196 | for (const Function &func : scope->functionList) { |
| 2197 | // does the function have a body? |
| 2198 | if (func.type != FunctionType::eFunction || !func.hasBody()) |
| 2199 | continue; |
| 2200 | // don't warn for friend/static/virtual functions |
| 2201 | if (func.isFriend() || func.isStatic() || func.hasVirtualSpecifier()) |
| 2202 | continue; |
| 2203 | if (func.functionPointerUsage) |
| 2204 | continue; |
| 2205 | if (func.hasRvalRefQualifier()) |
| 2206 | continue; |
| 2207 | |
| 2208 | // don't suggest const when returning non-const pointer/reference, but still suggest static |
| 2209 | auto isPointerOrReference = [this](const Token* start, const Token* end) -> bool { |
| 2210 | bool inTemplArgList = false, isConstTemplArg = false; |
| 2211 | for (const Token* tok = start; tok != end; tok = tok->next()) { |
| 2212 | if (tok->str() == "{") // end of trailing return type |
| 2213 | return false; |
| 2214 | if (tok->str() == "<") { |
| 2215 | if (!tok->link()) |
| 2216 | mSymbolDatabase->debugMessage(tok, "debug", "CheckClass::checkConst found unlinked template argument list '" + tok->expressionString() + "'."); |
| 2217 | inTemplArgList = true; |
| 2218 | } |
| 2219 | else if (tok->str() == ">") { |
| 2220 | inTemplArgList = false; |
| 2221 | isConstTemplArg = false; |
| 2222 | } |
| 2223 | else if (tok->str() == "const") { |
| 2224 | if (!inTemplArgList) |
| 2225 | return false; |
| 2226 | isConstTemplArg = true; |
| 2227 | } |
| 2228 | else if (!isConstTemplArg && Token::Match(tok, "*|&")) |
| 2229 | return true; |
| 2230 | } |
| 2231 | return false; |
| 2232 | }; |
| 2233 | |
| 2234 | const bool returnsPtrOrRef = isPointerOrReference(func.retDef, func.tokenDef); |
| 2235 | |
| 2236 | if (Function::returnsPointer(&func, /*unknown*/ true) || Function::returnsReference(&func, /*unknown*/ true, /*includeRValueRef*/ true)) { // returns const/non-const depending on template arg |
| 2237 | bool isTemplateArg = false; |
| 2238 | for (const Token* tok2 = func.retDef; precedes(tok2, func.token); tok2 = tok2->next()) |
| 2239 | if (tok2->isTemplateArg() && tok2->str() == "const") { |
| 2240 | isTemplateArg = true; |
| 2241 | break; |
| 2242 | } |
| 2243 | if (isTemplateArg) |
no test coverage detected