Haojian Wu | ada2862 | 2016-10-17 08:33:59 +0000 | [diff] [blame] | 1 | //===---------- UsingInserter.cpp - clang-tidy ----------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
| 10 | #include "UsingInserter.h" |
| 11 | |
| 12 | #include "ASTUtils.h" |
| 13 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
| 14 | #include "clang/ASTMatchers/ASTMatchers.h" |
| 15 | #include "clang/Lex/Lexer.h" |
| 16 | |
| 17 | namespace clang { |
| 18 | namespace tidy { |
| 19 | namespace utils { |
| 20 | |
| 21 | using namespace ast_matchers; |
| 22 | |
| 23 | static StringRef getUnqualifiedName(StringRef QualifiedName) { |
| 24 | size_t LastSeparatorPos = QualifiedName.rfind("::"); |
| 25 | if (LastSeparatorPos == StringRef::npos) |
| 26 | return QualifiedName; |
| 27 | return QualifiedName.drop_front(LastSeparatorPos + 2); |
| 28 | } |
| 29 | |
| 30 | UsingInserter::UsingInserter(const SourceManager &SourceMgr) |
| 31 | : SourceMgr(SourceMgr) {} |
| 32 | |
| 33 | Optional<FixItHint> UsingInserter::createUsingDeclaration( |
| 34 | ASTContext &Context, const Stmt &Statement, StringRef QualifiedName) { |
| 35 | StringRef UnqualifiedName = getUnqualifiedName(QualifiedName); |
| 36 | const FunctionDecl *Function = getSurroundingFunction(Context, Statement); |
| 37 | if (!Function) |
| 38 | return None; |
| 39 | |
| 40 | if (AddedUsing.count(std::make_pair(Function, QualifiedName.str())) != 0) |
| 41 | return None; |
| 42 | |
| 43 | SourceLocation InsertLoc = Lexer::getLocForEndOfToken( |
Stephen Kelly | 43465bf | 2018-08-09 22:42:26 +0000 | [diff] [blame] | 44 | Function->getBody()->getBeginLoc(), 0, SourceMgr, Context.getLangOpts()); |
Haojian Wu | ada2862 | 2016-10-17 08:33:59 +0000 | [diff] [blame] | 45 | |
| 46 | // Only use using declarations in the main file, not in includes. |
| 47 | if (SourceMgr.getFileID(InsertLoc) != SourceMgr.getMainFileID()) |
| 48 | return None; |
| 49 | |
| 50 | // FIXME: This declaration could be masked. Investigate if |
| 51 | // there is a way to avoid using Sema. |
| 52 | bool AlreadyHasUsingDecl = |
| 53 | !match(stmt(hasAncestor(decl(has(usingDecl(hasAnyUsingShadowDecl( |
| 54 | hasTargetDecl(hasName(QualifiedName.str())))))))), |
| 55 | Statement, Context) |
| 56 | .empty(); |
| 57 | if (AlreadyHasUsingDecl) { |
| 58 | AddedUsing.emplace(NameInFunction(Function, QualifiedName.str())); |
| 59 | return None; |
| 60 | } |
| 61 | // Find conflicting declarations and references. |
| 62 | auto ConflictingDecl = namedDecl(hasName(UnqualifiedName)); |
| 63 | bool HasConflictingDeclaration = |
| 64 | !match(findAll(ConflictingDecl), *Function, Context).empty(); |
| 65 | bool HasConflictingDeclRef = |
| 66 | !match(findAll(declRefExpr(to(ConflictingDecl))), *Function, Context) |
| 67 | .empty(); |
| 68 | if (HasConflictingDeclaration || HasConflictingDeclRef) |
| 69 | return None; |
| 70 | |
Mandeep Singh Grang | 7c7ea7d | 2016-11-08 07:50:19 +0000 | [diff] [blame] | 71 | std::string Declaration = |
| 72 | (llvm::Twine("\nusing ") + QualifiedName + ";").str(); |
Haojian Wu | ada2862 | 2016-10-17 08:33:59 +0000 | [diff] [blame] | 73 | |
| 74 | AddedUsing.emplace(std::make_pair(Function, QualifiedName.str())); |
| 75 | return FixItHint::CreateInsertion(InsertLoc, Declaration); |
| 76 | } |
| 77 | |
| 78 | StringRef UsingInserter::getShortName(ASTContext &Context, |
| 79 | const Stmt &Statement, |
| 80 | StringRef QualifiedName) { |
| 81 | const FunctionDecl *Function = getSurroundingFunction(Context, Statement); |
| 82 | if (AddedUsing.count(NameInFunction(Function, QualifiedName.str())) != 0) |
| 83 | return getUnqualifiedName(QualifiedName); |
| 84 | return QualifiedName; |
| 85 | } |
| 86 | |
| 87 | } // namespace utils |
| 88 | } // namespace tidy |
| 89 | } // namespace clang |