59 AnalyzePointers(Options.get(
"AnalyzePointers", true)),
60 AnalyzeReferences(Options.get(
"AnalyzeReferences", true)),
61 AnalyzeValues(Options.get(
"AnalyzeValues", true)),
62 AnalyzeAutoVariables(Options.get(
"AnalyzeAutoVariables", true)),
63 AnalyzeLambdas(Options.get(
"AnalyzeLambdas", true)),
64 AnalyzeParameters(Options.get(
"AnalyzeParameters", true)),
66 WarnPointersAsPointers(Options.get(
"WarnPointersAsPointers", true)),
67 WarnPointersAsValues(Options.get(
"WarnPointersAsValues", false)),
69 TransformPointersAsPointers(
70 Options.get(
"TransformPointersAsPointers", true)),
71 TransformPointersAsValues(
72 Options.get(
"TransformPointersAsValues", false)),
73 TransformReferences(Options.get(
"TransformReferences", true)),
74 TransformValues(Options.get(
"TransformValues", true)),
77 utils::options::parseStringList(Options.get(
"AllowedTypes",
""))) {
78 if (AnalyzeValues ==
false && AnalyzeReferences ==
false &&
79 AnalyzePointers ==
false)
80 this->configurationDiag(
81 "The check 'misc-const-correctness' will not "
82 "perform any analysis because 'AnalyzeValues', "
83 "'AnalyzeReferences' and 'AnalyzePointers' are false.");
85 if (AnalyzeLambdas && !AnalyzeAutoVariables)
86 this->configurationDiag(
"The check 'misc-const-correctness' will not "
87 "analyze lambdas because 'AnalyzeLambdas' has no "
88 "effect while 'AnalyzeAutoVariables' is false.");
113 const auto ConstType =
114 hasType(qualType(isConstQualified(),
116 unless(pointerType())));
118 const auto ConstReference = hasType(references(isConstQualified()));
119 const auto RValueReference = hasType(
120 referenceType(anyOf(rValueReferenceType(), unless(isSpelledAsLValue()))));
122 const auto TemplateType = anyOf(
123 hasType(hasCanonicalType(templateTypeParmType())),
124 hasType(substTemplateTypeParmType()), hasType(isDependentType()),
127 hasType(referenceType(pointee(hasCanonicalType(templateTypeParmType())))),
128 hasType(referenceType(pointee(substTemplateTypeParmType()))));
130 const auto AllowedTypeDecl = namedDecl(anyOf(
133 const auto AllowedType = hasType(qualType(
134 anyOf(hasDeclaration(AllowedTypeDecl), references(AllowedTypeDecl),
135 pointerType(pointee(hasDeclaration(AllowedTypeDecl))))));
137 const auto AutoTemplateType = varDecl(
138 anyOf(hasType(autoType()), hasType(referenceType(pointee(autoType()))),
139 hasType(pointerType(pointee(autoType())))));
141 const auto FunctionPointerRef =
142 hasType(hasCanonicalType(referenceType(pointee(functionType()))));
145 const auto DecltypeAutoType =
146 hasType(ignoringParens(autoType(isDecltypeAuto())));
148 const auto CommonExcludeTypes =
149 anyOf(ConstType, ConstReference, RValueReference, TemplateType,
150 FunctionPointerRef, hasType(cxxRecordDecl(isLambda())),
151 AutoTemplateType, isImplicit(), AllowedType);
155 const auto LocalValDecl = varDecl(
156 isLocalVarDecl(), hasInitializer(anything()),
157 unless(anyOf(ConstType, ConstReference, TemplateType,
158 hasInitializer(isInstantiationDependent()), RValueReference,
159 FunctionPointerRef, isImplicit(), AllowedType,
162 ? Matcher<VarDecl>(anything())
163 : Matcher<VarDecl>(unless(hasType(cxxRecordDecl(isLambda())))),
165 ? Matcher<VarDecl>(anything())
166 : Matcher<VarDecl>(unless(hasTypeLoc(hasContainedAutoType()))));
170 const auto FunctionScope =
171 functionDecl(hasBody(stmt(forEachDescendant(
172 declStmt(containsAnyDeclaration(
173 LocalValDecl.bind(
"value")),
174 unless(has(decompositionDecl())))
177 .bind(
"function-decl");
179 Finder->addMatcher(FunctionScope,
this);
181 if (AnalyzeParameters) {
182 const auto ParamMatcher =
183 parmVarDecl(unless(CommonExcludeTypes), unless(isUnnamed()),
184 anyOf(hasType(referenceType()), hasType(pointerType())))
189 const auto FunctionWithParams =
191 hasBody(stmt().bind(
"scope")), has(typeLoc(forEach(ParamMatcher))),
192 unless(cxxMethodDecl()), unless(isMain()),
193 unless(isFunctionTemplateSpecialization()), unless(isTemplate()))
194 .bind(
"function-decl");
196 Finder->addMatcher(FunctionWithParams,
this);
220 const VarDecl *Variable,
221 const FunctionDecl *Function,
222 const ASTContext &Context, Qualifiers::TQ Qualifier,
227 if (
const auto *ParamDecl = dyn_cast<ParmVarDecl>(Variable)) {
228 const unsigned ParamIdx = ParamDecl->getFunctionScopeIndex();
231 Function->redecls(), [ParamIdx](
const FunctionDecl *Redecl) {
232 const QualType Type = Redecl->getParamDecl(ParamIdx)->getType();
233 return Type->isTypedefNameType() || Type->getAs<UsingType>();
237 for (
const FunctionDecl *Redecl : Function->redecls()) {
238 Diag << addQualifierToVarDecl(*Redecl->getParamDecl(ParamIdx), Context,
239 Qualifier, Target, Policy);
242 Diag << addQualifierToVarDecl(*Variable, Context, Qualifier, Target,
255 const auto *LocalScope = Result.Nodes.getNodeAs<Stmt>(
"scope");
256 const auto *Variable = Result.Nodes.getNodeAs<VarDecl>(
"value");
257 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>(
"function-decl");
258 const auto *VarDeclStmt = Result.Nodes.getNodeAs<DeclStmt>(
"decl-stmt");
260 assert(Variable && LocalScope && Function);
266 const bool CanBeFixIt = isa<ParmVarDecl>(Variable) ||
267 (VarDeclStmt && VarDeclStmt->isSingleDecl());
274 bool IsNormalVariableInTemplate = Function->isTemplateInstantiation();
276 VariableCategory VC = VariableCategory::Value;
277 const QualType VT = Variable->getType();
278 if (VT->isReferenceType())
279 VC = VariableCategory::Reference;
280 else if (VT->isPointerType())
281 VC = VariableCategory::Pointer;
282 else if (
const auto *ArrayT = dyn_cast<ArrayType>(VT);
283 ArrayT && ArrayT->getElementType()->isPointerType())
284 VC = VariableCategory::Pointer;
286 if (IsNormalVariableInTemplate && VC != VariableCategory::Pointer &&
290 if (IsNormalVariableInTemplate &&
291 TemplateDiagnosticsCache.contains(Variable->getBeginLoc()))
294 const auto CheckValue = [&]() {
296 if (isMutated(Variable, LocalScope, Function, Result.Context))
299 const auto Diag = diag(Variable->getBeginLoc(),
300 "variable %0 of type %1 can be declared 'const'")
302 if (IsNormalVariableInTemplate)
303 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
308 if (VC == VariableCategory::Value && TransformValues) {
310 Qualifiers::Const, QualifierTarget::Value,
311 QualifierPolicy::Right);
317 if (VC == VariableCategory::Reference && TransformReferences) {
319 Qualifiers::Const, QualifierTarget::Value,
320 QualifierPolicy::Right);
324 if (VC == VariableCategory::Pointer && TransformPointersAsValues) {
326 Qualifiers::Const, QualifierTarget::Value,
327 QualifierPolicy::Right);
332 const auto CheckPointee = [&]() {
333 assert(VC == VariableCategory::Pointer);
334 registerScope(LocalScope, Result.Context);
335 if (ScopesCache[LocalScope]->isPointeeMutated(Variable))
338 diag(Variable->getBeginLoc(),
339 "pointee of variable %0 of type %1 can be declared 'const'")
341 if (IsNormalVariableInTemplate)
342 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
346 if (TransformPointersAsPointers) {
348 Qualifiers::Const, QualifierTarget::Pointee,
349 QualifierPolicy::Right);
355 if (VC == VariableCategory::Value && AnalyzeValues) {
359 if (VC == VariableCategory::Reference && AnalyzeReferences) {
360 if (VT->getPointeeType()->isPointerType() && !WarnPointersAsValues)
365 if (VC == VariableCategory::Pointer && AnalyzePointers) {
366 if (WarnPointersAsValues && !VT.isConstQualified())
368 if (WarnPointersAsPointers) {
369 if (
const auto *PT = dyn_cast<PointerType>(VT);
370 PT && !PT->getPointeeType().isConstQualified() &&
371 !PT->getPointeeType()->isFunctionType())
374 if (
const auto *AT = dyn_cast<ArrayType>(VT)) {
375 assert(AT->getElementType()->isPointerType());
376 if (!AT->getElementType()->getPointeeType().isConstQualified())
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.