blob: 80aa1bc6dd2c74077f83b78f1b019e8288ccb35b [file] [log] [blame]
//===--- RenamingOperation.cpp - ------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Refactor/RenamingOperation.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Refactor/SymbolOperation.h"
using namespace clang;
/// \brief Lexes the given name string.
///
/// \return False if the name was consumed fully, true otherwise.
static bool lexNameString(StringRef Name, Token &Result,
const LangOptions &LangOpts) {
Lexer Lex(SourceLocation(), LangOpts, Name.data(), Name.data(),
Name.data() + Name.size());
return !Lex.LexFromRawLexer(Result);
}
namespace clang {
namespace tooling {
namespace rename {
bool isNewNameValid(const SymbolName &NewName, bool IsSymbolObjCSelector,
IdentifierTable &IDs, const LangOptions &LangOpts) {
Token Tok;
if (IsSymbolObjCSelector) {
// Check if the name is a valid selector.
for (const auto &Name : NewName.strings()) {
// Lex the name and verify that it was fully consumed. Then make sure that
// it's a valid identifier.
if (lexNameString(Name, Tok, LangOpts) || !Tok.isAnyIdentifier())
return false;
}
return true;
}
for (const auto &Name : NewName.strings()) {
// Lex the name and verify that it was fully consumed. Then make sure that
// it's a valid identifier that's also not a language keyword.
if (lexNameString(Name, Tok, LangOpts) || !Tok.isAnyIdentifier() ||
!tok::isAnyIdentifier(IDs.get(Name).getTokenID()))
return false;
}
return true;
}
bool isNewNameValid(const SymbolName &NewName, const SymbolOperation &Operation,
IdentifierTable &IDs, const LangOptions &LangOpts) {
assert(!Operation.symbols().empty());
return isNewNameValid(NewName,
Operation.symbols().front().ObjCSelector.hasValue(),
IDs, LangOpts);
}
void determineNewNames(SymbolName NewName, const SymbolOperation &Operation,
SmallVectorImpl<SymbolName> &NewNames,
const LangOptions &LangOpts) {
auto Symbols = Operation.symbols();
assert(!Symbols.empty());
NewNames.push_back(std::move(NewName));
if (const auto *PropertyDecl =
dyn_cast<ObjCPropertyDecl>(Symbols.front().FoundDecl)) {
assert(NewNames.front().size() == 1 &&
"Property's name should have one string only");
StringRef PropertyName = NewNames.front()[0];
Symbols = Symbols.drop_front();
auto AddName = [&](const NamedDecl *D, StringRef Name) {
assert(Symbols.front().FoundDecl == D && "decl is missing");
NewNames.push_back(SymbolName(Name, LangOpts));
Symbols = Symbols.drop_front();
};
if (!PropertyDecl->hasExplicitGetterName()) {
if (const auto *Getter = PropertyDecl->getGetterMethodDecl())
AddName(Getter, PropertyName);
}
if (!PropertyDecl->hasExplicitSetterName()) {
if (const auto *Setter = PropertyDecl->getSetterMethodDecl()) {
auto SetterName = SelectorTable::constructSetterName(PropertyName);
AddName(Setter, SetterName);
}
}
}
}
} // end namespace rename
} // end namespace tooling
} // end namespace clang