12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- //===---------- UsingInserter.cpp - clang-tidy ----------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "UsingInserter.h"
- #include "ASTUtils.h"
- #include "clang/ASTMatchers/ASTMatchFinder.h"
- #include "clang/ASTMatchers/ASTMatchers.h"
- #include "clang/Lex/Lexer.h"
- #include <optional>
- namespace clang::tidy::utils {
- using namespace ast_matchers;
- static StringRef getUnqualifiedName(StringRef QualifiedName) {
- size_t LastSeparatorPos = QualifiedName.rfind("::");
- if (LastSeparatorPos == StringRef::npos)
- return QualifiedName;
- return QualifiedName.drop_front(LastSeparatorPos + 2);
- }
- UsingInserter::UsingInserter(const SourceManager &SourceMgr)
- : SourceMgr(SourceMgr) {}
- std::optional<FixItHint> UsingInserter::createUsingDeclaration(
- ASTContext &Context, const Stmt &Statement, StringRef QualifiedName) {
- StringRef UnqualifiedName = getUnqualifiedName(QualifiedName);
- const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
- if (!Function)
- return std::nullopt;
- if (AddedUsing.count(std::make_pair(Function, QualifiedName.str())) != 0)
- return std::nullopt;
- SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
- Function->getBody()->getBeginLoc(), 0, SourceMgr, Context.getLangOpts());
- // Only use using declarations in the main file, not in includes.
- if (SourceMgr.getFileID(InsertLoc) != SourceMgr.getMainFileID())
- return std::nullopt;
- // FIXME: This declaration could be masked. Investigate if
- // there is a way to avoid using Sema.
- bool AlreadyHasUsingDecl =
- !match(stmt(hasAncestor(decl(has(usingDecl(hasAnyUsingShadowDecl(
- hasTargetDecl(hasName(QualifiedName.str())))))))),
- Statement, Context)
- .empty();
- if (AlreadyHasUsingDecl) {
- AddedUsing.emplace(NameInFunction(Function, QualifiedName.str()));
- return std::nullopt;
- }
- // Find conflicting declarations and references.
- auto ConflictingDecl = namedDecl(hasName(UnqualifiedName));
- bool HasConflictingDeclaration =
- !match(findAll(ConflictingDecl), *Function, Context).empty();
- bool HasConflictingDeclRef =
- !match(findAll(declRefExpr(to(ConflictingDecl))), *Function, Context)
- .empty();
- if (HasConflictingDeclaration || HasConflictingDeclRef)
- return std::nullopt;
- std::string Declaration =
- (llvm::Twine("\nusing ") + QualifiedName + ";").str();
- AddedUsing.emplace(std::make_pair(Function, QualifiedName.str()));
- return FixItHint::CreateInsertion(InsertLoc, Declaration);
- }
- StringRef UsingInserter::getShortName(ASTContext &Context,
- const Stmt &Statement,
- StringRef QualifiedName) {
- const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
- if (AddedUsing.count(NameInFunction(Function, QualifiedName.str())) != 0)
- return getUnqualifiedName(QualifiedName);
- return QualifiedName;
- }
- } // namespace clang::tidy::utils
|