Skip to content

Instantly share code, notes, and snippets.

@chichunchen
Created April 20, 2019 20:15
Show Gist options
  • Save chichunchen/76fdbcb3bf04a94c3ab007ada2623785 to your computer and use it in GitHub Desktop.
Save chichunchen/76fdbcb3bf04a94c3ab007ada2623785 to your computer and use it in GitHub Desktop.
class Checker : public clang::ast_matchers::MatchFinder::MatchCallback {
public:
using MatchResult = clang::ast_matchers::MatchFinder::MatchResult;
Checker(bool RewriteOption, clang::Rewriter &Rewriter)
: RewriteOption(RewriteOption), Rewriter(Rewriter) {}
void run(const MatchResult &Result) {
const auto *Target = Result.Nodes.getNodeAs<clang::CXXMethodDecl>("target");
if (!needsOverride(*Target))
return;
auto &Diagnostics = Result.Context->getDiagnostics();
const auto ID =
Diagnostics.getCustomDiagID(clang::DiagnosticsEngine::Warning,
"method '%0' should be declared override");
clang::SourceLocation InsertionPoint =
findInsertionPoint(*Target, *Result.Context);
clang::DiagnosticBuilder Diagnostic =
Diagnostics.Report(InsertionPoint, ID);
Diagnostic.AddString(Target->getName());
if (RewriteOption) {
Rewriter.InsertText(InsertionPoint, " override ");
} else {
const auto FixIt =
clang::FixItHint::CreateInsertion(InsertionPoint, "override");
Diagnostic.AddFixItHint(FixIt);
}
}
private:
bool RewriteOption;
clang::Rewriter &Rewriter;
bool needsOverride(const clang::CXXMethodDecl &MethodDecl) {
if (!MethodDecl.size_overridden_methods())
return false;
const auto &Attrs = MethodDecl.getAttrs();
return std::none_of(Attrs.begin(), Attrs.end(), [](const auto *Attr) {
return Attr->getSpelling() == "override";
});
}
clang::SourceLocation
findInsertionPoint(const clang::CXXMethodDecl &MethodDecl,
const clang::ASTContext &Context) {
clang::SourceLocation Location;
/// Find the end of the parameter list.
if (MethodDecl.param_empty()) {
const unsigned Offset = MethodDecl.getName().size();
Location = MethodDecl.getLocation().getLocWithOffset(Offset);
} else {
const clang::ParmVarDecl *Last = *std::prev(MethodDecl.param_end());
Location = Last->getEndLoc();
}
Location = clang::Lexer::findLocationAfterToken(
Location, clang::tok::r_paren, Context.getSourceManager(),
Context.getLangOpts(),
/*skipWhiteSpace=*/true);
return Location.getLocWithOffset(-1);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment