+ CheckVirtualSpecifiers(*it);
+ if (warn_on_inline_bodies)
+ CheckVirtualBodies(*it);
+ }
+ }
+}
+
+// Makes sure that virtual methods use the most appropriate specifier. If a
+// virtual method overrides a method from a base class, only the override
+// specifier should be used. If the method should not be overridden by derived
+// classes, only the final specifier should be used.
+void FindBadConstructsConsumer::CheckVirtualSpecifiers(
+ const CXXMethodDecl* method) {
+ bool is_override = method->size_overridden_methods() > 0;
+ bool has_virtual = method->isVirtualAsWritten();
+ OverrideAttr* override_attr = method->getAttr<OverrideAttr>();
+ FinalAttr* final_attr = method->getAttr<FinalAttr>();
+
+ if (method->isPure() && !options_.strict_virtual_specifiers)
+ return;
+
+ if (IsMethodInBannedOrTestingNamespace(method))
+ return;
+
+ if (isa<CXXDestructorDecl>(method) && !options_.strict_virtual_specifiers)
+ return;
+
+ SourceManager& manager = instance().getSourceManager();
+
+ // Complain if a method is annotated virtual && (override || final).
+ if (has_virtual && (override_attr || final_attr) &&
+ options_.strict_virtual_specifiers) {
+ diagnostic().Report(method->getLocStart(),
+ diag_redundant_virtual_specifier_)
+ << "'virtual'"
+ << (override_attr ? static_cast<Attr*>(override_attr) : final_attr)
+ << FixItRemovalForVirtual(manager, method);
+ }
+
+ // Complain if a method is an override and is not annotated with override or
+ // final.
+ if (is_override && !override_attr && !final_attr) {
+ SourceRange type_info_range =
+ method->getTypeSourceInfo()->getTypeLoc().getSourceRange();
+ FullSourceLoc loc(type_info_range.getBegin(), manager);
+
+ // Build the FixIt insertion point after the end of the method definition,
+ // including any const-qualifiers and attributes, and before the opening
+ // of the l-curly-brace (if inline) or the semi-color (if a declaration).
+ SourceLocation spelling_end =
+ manager.getSpellingLoc(type_info_range.getEnd());
+ if (spelling_end.isValid()) {
+ SourceLocation token_end =
+ Lexer::getLocForEndOfToken(spelling_end, 0, manager, LangOptions());
+ diagnostic().Report(token_end, diag_method_requires_override_)
+ << FixItHint::CreateInsertion(token_end, " override");
+ } else {
+ diagnostic().Report(loc, diag_method_requires_override_);
+ }
+ }
+
+ if (final_attr && override_attr && options_.strict_virtual_specifiers) {
+ diagnostic().Report(override_attr->getLocation(),
+ diag_redundant_virtual_specifier_)
+ << override_attr << final_attr
+ << FixItHint::CreateRemoval(override_attr->getRange());
+ }
+
+ if (final_attr && !is_override && options_.strict_virtual_specifiers) {
+ diagnostic().Report(method->getLocStart(),
+ diag_base_method_virtual_and_final_)
+ << FixItRemovalForVirtual(manager, method)
+ << FixItHint::CreateRemoval(final_attr->getRange());
+ }
+}
+
+void FindBadConstructsConsumer::CheckVirtualBodies(
+ const CXXMethodDecl* method) {
+ // Virtual methods should not have inline definitions beyond "{}". This
+ // only matters for header files.
+ if (method->hasBody() && method->hasInlineBody()) {
+ if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) {
+ if (cs->size()) {
+ emitWarning(cs->getLBracLoc(),
+ "virtual methods with non-empty bodies shouldn't be "
+ "declared inline.");
+ }