blob: f2392e419c8e533a0ccafd3c5cae7f9cf126c326 [file] [log] [blame]
//===--- IndexerQueries.cpp - Indexer queries -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Core/RefactoringDiagnostic.h"
#include "clang/Tooling/Refactor/IndexerQuery.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/YAMLTraits.h"
using namespace clang;
using namespace clang::tooling;
using namespace clang::tooling::indexer;
using namespace clang::tooling::indexer::detail;
using namespace llvm::yaml;
const char *ASTProducerQuery::BaseUIDString = "ast.producer.query";
const char *DeclarationsQuery::BaseUIDString = "decl.query";
const char *ASTUnitForImplementationOfDeclarationQuery::NameUIDString =
"file.for.impl.of.decl";
const char *DeclPredicateNodePredicate::NameUIDString = "decl.predicate";
const char *DeclPredicateNotPredicate::NameUIDString = "not.decl.predicate";
std::unique_ptr<DeclPredicateNode>
DeclPredicateNode::create(const DeclPredicate &Predicate) {
return llvm::make_unique<DeclPredicateNodePredicate>(Predicate);
}
std::unique_ptr<DeclPredicateNode>
DeclPredicateNode::create(const BoolDeclPredicate &Predicate) {
if (Predicate.IsInverted)
return llvm::make_unique<DeclPredicateNotPredicate>(
create(Predicate.Predicate));
return create(Predicate.Predicate);
}
std::unique_ptr<ASTUnitForImplementationOfDeclarationQuery>
clang::tooling::indexer::fileThatShouldContainImplementationOf(const Decl *D) {
return llvm::make_unique<ASTUnitForImplementationOfDeclarationQuery>(D);
}
bool ASTUnitForImplementationOfDeclarationQuery::verify(ASTContext &Context) {
if (!D) {
assert(false && "Query should be verified before persisting");
return false;
}
// Check if we've got the filename.
if (!Result.Filename.empty())
return false;
Context.getDiagnostics().Report(
D->getLocation(), diag::err_ref_continuation_missing_implementation)
<< isa<ObjCContainerDecl>(D) << cast<NamedDecl>(D);
return true;
}
bool DeclarationsQuery::verify(ASTContext &Context) {
if (Input.empty()) {
assert(false && "Query should be verified before persisting");
return false;
}
if (!Output.empty()) {
// At least one output declaration must be valid.
for (const auto &Ref : Output) {
if (!Ref.Decl.USR.empty())
return false;
}
}
// FIXME: This is too specific, the new refactoring engine at llvm.org should
// generalize this.
Context.getDiagnostics().Report(
Input[0]->getLocation(),
diag::err_implement_declared_methods_all_implemented);
return true;
}
namespace {
struct QueryPredicateNode {
std::string Name;
std::vector<int> IntegerValues;
};
struct QueryYAMLNode {
std::string Name;
std::vector<QueryPredicateNode> PredicateResults;
std::string FilenameResult;
};
} // end anonymous namespace
LLVM_YAML_IS_SEQUENCE_VECTOR(QueryPredicateNode)
LLVM_YAML_IS_SEQUENCE_VECTOR(QueryYAMLNode)
namespace llvm {
namespace yaml {
template <> struct MappingTraits<QueryPredicateNode> {
static void mapping(IO &Yaml, QueryPredicateNode &Predicate) {
Yaml.mapRequired("name", Predicate.Name);
Yaml.mapRequired("intValues", Predicate.IntegerValues);
}
};
template <> struct MappingTraits<QueryYAMLNode> {
static void mapping(IO &Yaml, QueryYAMLNode &Query) {
Yaml.mapRequired("name", Query.Name);
Yaml.mapOptional("predicateResults", Query.PredicateResults);
Yaml.mapOptional("filenameResult", Query.FilenameResult);
// FIXME: Report an error if no results are provided at all.
}
};
} // end namespace yaml
} // end namespace llvm
llvm::Error
IndexerQuery::loadResultsFromYAML(StringRef Source,
ArrayRef<IndexerQuery *> Queries) {
std::vector<QueryYAMLNode> QueryResults;
Input YamlIn(Source);
YamlIn >> QueryResults;
if (YamlIn.error())
return llvm::make_error<llvm::StringError>("Failed to parse query results",
YamlIn.error());
if (QueryResults.size() != Queries.size())
return llvm::make_error<llvm::StringError>("Mismatch in query results size",
llvm::errc::invalid_argument);
for (const auto &QueryTuple : llvm::zip(Queries, QueryResults)) {
IndexerQuery *Query = std::get<0>(QueryTuple);
const QueryYAMLNode &Result = std::get<1>(QueryTuple);
if ((Query->NameUID && Query->NameUID != Result.Name) &&
(Query->BaseUID && Query->BaseUID != Result.Name))
continue;
if (auto *DQ = dyn_cast<DeclarationsQuery>(Query)) {
const DeclPredicateNode &Predicate = DQ->getPredicateNode();
DeclPredicate ActualPredicate("");
bool IsNot = false;
if (const auto *Not = dyn_cast<DeclPredicateNotPredicate>(&Predicate)) {
ActualPredicate =
cast<DeclPredicateNodePredicate>(Not->getChild()).getPredicate();
IsNot = true;
} else
ActualPredicate =
cast<DeclPredicateNodePredicate>(Predicate).getPredicate();
for (const auto &PredicateResult : Result.PredicateResults) {
if (PredicateResult.Name != ActualPredicate.Name)
continue;
std::vector<Indexed<PersistentDeclRef<Decl>>> Output;
for (const auto &ResultTuple :
zip(DQ->getInputs(), PredicateResult.IntegerValues)) {
const Decl *D = std::get<0>(ResultTuple);
int Result = std::get<1>(ResultTuple);
bool Value = (IsNot ? !Result : !!Result);
Output.push_back(Indexed<PersistentDeclRef<Decl>>(
PersistentDeclRef<Decl>::create(Value ? D : nullptr),
Value ? QueryBoolResult::Yes : QueryBoolResult::No));
}
DQ->setOutput(std::move(Output));
break;
}
} else if (auto *AQ =
dyn_cast<ASTUnitForImplementationOfDeclarationQuery>(Query))
AQ->setResult(Result.FilenameResult);
}
return llvm::Error::success();
}