49 AnalyzePointers(Options.get(
"AnalyzePointers", true)),
50 AnalyzeReferences(Options.get(
"AnalyzeReferences", true)),
51 AnalyzeValues(Options.get(
"AnalyzeValues", true)),
52 AnalyzeParameters(Options.get(
"AnalyzeParameters", true)),
54 WarnPointersAsPointers(Options.get(
"WarnPointersAsPointers", true)),
55 WarnPointersAsValues(Options.get(
"WarnPointersAsValues", false)),
57 TransformPointersAsPointers(
58 Options.get(
"TransformPointersAsPointers", true)),
59 TransformPointersAsValues(
60 Options.get(
"TransformPointersAsValues", false)),
61 TransformReferences(Options.get(
"TransformReferences", true)),
62 TransformValues(Options.get(
"TransformValues", true)),
65 utils::options::parseStringList(Options.get(
"AllowedTypes",
""))) {
66 if (AnalyzeValues ==
false && AnalyzeReferences ==
false &&
67 AnalyzePointers ==
false)
68 this->configurationDiag(
69 "The check 'misc-const-correctness' will not "
70 "perform any analysis because 'AnalyzeValues', "
71 "'AnalyzeReferences' and 'AnalyzePointers' are false.");
94 const auto ConstType =
95 hasType(qualType(isConstQualified(),
97 unless(pointerType())));
99 const auto ConstReference = hasType(references(isConstQualified()));
100 const auto RValueReference = hasType(
101 referenceType(anyOf(rValueReferenceType(), unless(isSpelledAsLValue()))));
103 const auto TemplateType = anyOf(
104 hasType(hasCanonicalType(templateTypeParmType())),
105 hasType(substTemplateTypeParmType()), hasType(isDependentType()),
108 hasType(referenceType(pointee(hasCanonicalType(templateTypeParmType())))),
109 hasType(referenceType(pointee(substTemplateTypeParmType()))));
111 auto AllowedTypeDecl = namedDecl(anyOf(
114 const auto AllowedType = hasType(qualType(
115 anyOf(hasDeclaration(AllowedTypeDecl), references(AllowedTypeDecl),
116 pointerType(pointee(hasDeclaration(AllowedTypeDecl))))));
118 const auto AutoTemplateType = varDecl(
119 anyOf(hasType(autoType()), hasType(referenceType(pointee(autoType()))),
120 hasType(pointerType(pointee(autoType())))));
122 const auto FunctionPointerRef =
123 hasType(hasCanonicalType(referenceType(pointee(functionType()))));
125 const auto CommonExcludeTypes =
126 anyOf(ConstType, ConstReference, RValueReference, TemplateType,
127 FunctionPointerRef, hasType(cxxRecordDecl(isLambda())),
128 AutoTemplateType, isImplicit(), AllowedType);
132 const auto LocalValDecl =
133 varDecl(isLocal(), hasInitializer(unless(isInstantiationDependent())),
134 unless(CommonExcludeTypes));
138 const auto FunctionScope =
139 functionDecl(hasBody(stmt(forEachDescendant(
140 declStmt(containsAnyDeclaration(
141 LocalValDecl.bind(
"value")),
142 unless(has(decompositionDecl())))
145 .bind(
"function-decl");
147 Finder->addMatcher(FunctionScope,
this);
149 if (AnalyzeParameters) {
150 const auto ParamMatcher =
151 parmVarDecl(unless(CommonExcludeTypes),
152 anyOf(hasType(referenceType()), hasType(pointerType())))
157 const auto FunctionWithParams =
159 hasBody(stmt().bind(
"scope")), has(typeLoc(forEach(ParamMatcher))),
160 unless(cxxMethodDecl()), unless(isFunctionTemplateSpecialization()),
161 unless(isTemplate()))
162 .bind(
"function-decl");
164 Finder->addMatcher(FunctionWithParams,
this);
169 const FunctionDecl *Function, ASTContext &Context,
170 Qualifiers::TQ Qualifier,
175 if (
const auto *ParamDecl = dyn_cast<ParmVarDecl>(Variable)) {
176 const unsigned ParamIdx = ParamDecl->getFunctionScopeIndex();
179 Function->redecls(), [ParamIdx](
const FunctionDecl *Redecl) {
180 const QualType Type = Redecl->getParamDecl(ParamIdx)->getType();
181 return Type->isTypedefNameType() || Type->getAs<UsingType>();
185 for (
const FunctionDecl *Redecl : Function->redecls()) {
186 Diag << addQualifierToVarDecl(*Redecl->getParamDecl(ParamIdx), Context,
187 Qualifier, Target, Policy);
190 Diag << addQualifierToVarDecl(*Variable, Context, Qualifier, Target,
203 const auto *LocalScope = Result.Nodes.getNodeAs<Stmt>(
"scope");
204 const auto *Variable = Result.Nodes.getNodeAs<VarDecl>(
"value");
205 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>(
"function-decl");
206 const auto *VarDeclStmt = Result.Nodes.getNodeAs<DeclStmt>(
"decl-stmt");
208 assert(Variable && LocalScope && Function);
214 const bool CanBeFixIt = isa<ParmVarDecl>(Variable) ||
215 (VarDeclStmt && VarDeclStmt->isSingleDecl());
222 bool IsNormalVariableInTemplate = Function->isTemplateInstantiation();
223 if (IsNormalVariableInTemplate &&
224 TemplateDiagnosticsCache.contains(Variable->getBeginLoc()))
227 VariableCategory VC = VariableCategory::Value;
228 const QualType VT = Variable->getType();
229 if (VT->isReferenceType()) {
230 VC = VariableCategory::Reference;
231 }
else if (VT->isPointerType()) {
232 VC = VariableCategory::Pointer;
233 }
else if (
const auto *ArrayT = dyn_cast<ArrayType>(VT)) {
234 if (ArrayT->getElementType()->isPointerType())
235 VC = VariableCategory::Pointer;
238 auto CheckValue = [&]() {
240 if (isMutated(Variable, LocalScope, Function, Result.Context))
243 auto Diag = diag(Variable->getBeginLoc(),
244 "variable %0 of type %1 can be declared 'const'")
246 if (IsNormalVariableInTemplate)
247 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
252 if (VC == VariableCategory::Value && TransformValues) {
254 Qualifiers::Const, QualifierTarget::Value,
255 QualifierPolicy::Right);
261 if (VC == VariableCategory::Reference && TransformReferences) {
263 Qualifiers::Const, QualifierTarget::Value,
264 QualifierPolicy::Right);
268 if (VC == VariableCategory::Pointer && TransformPointersAsValues) {
270 Qualifiers::Const, QualifierTarget::Value,
271 QualifierPolicy::Right);
276 auto CheckPointee = [&]() {
277 assert(VC == VariableCategory::Pointer);
278 registerScope(LocalScope, Result.Context);
279 if (ScopesCache[LocalScope]->isPointeeMutated(Variable))
282 diag(Variable->getBeginLoc(),
283 "pointee of variable %0 of type %1 can be declared 'const'")
285 if (IsNormalVariableInTemplate)
286 TemplateDiagnosticsCache.insert(Variable->getBeginLoc());
290 if (TransformPointersAsPointers) {
292 Qualifiers::Const, QualifierTarget::Pointee,
293 QualifierPolicy::Right);
299 if (VC == VariableCategory::Value && AnalyzeValues) {
303 if (VC == VariableCategory::Reference && AnalyzeReferences) {
304 if (VT->getPointeeType()->isPointerType() && !WarnPointersAsValues)
309 if (VC == VariableCategory::Pointer && AnalyzePointers) {
310 if (WarnPointersAsValues && !VT.isConstQualified())
312 if (WarnPointersAsPointers) {
313 if (
const auto *PT = dyn_cast<PointerType>(VT)) {
314 if (!PT->getPointeeType().isConstQualified() &&
315 !PT->getPointeeType()->isFunctionType())
318 if (
const auto *AT = dyn_cast<ArrayType>(VT)) {
319 if (!AT->getElementType().isConstQualified()) {
320 assert(AT->getElementType()->isPointerType());
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.