Merge "Let header-abi-dumper declare unknown types automatically"
am: fcafbf84ee
Change-Id: If005234add470892bc7e15188c38756d4ef3733a
This commit is contained in:
@@ -56,6 +56,7 @@ cc_binary_host {
|
|||||||
"header-abi-dumper/src/abi_wrappers.cpp",
|
"header-abi-dumper/src/abi_wrappers.cpp",
|
||||||
"header-abi-dumper/src/ast_processing.cpp",
|
"header-abi-dumper/src/ast_processing.cpp",
|
||||||
"header-abi-dumper/src/diagnostic_consumer.cpp",
|
"header-abi-dumper/src/diagnostic_consumer.cpp",
|
||||||
|
"header-abi-dumper/src/fake_decl_source.cpp",
|
||||||
"header-abi-dumper/src/fixed_argv.cpp",
|
"header-abi-dumper/src/fixed_argv.cpp",
|
||||||
"header-abi-dumper/src/frontend_action.cpp",
|
"header-abi-dumper/src/frontend_action.cpp",
|
||||||
"header-abi-dumper/src/frontend_action_factory.cpp",
|
"header-abi-dumper/src/frontend_action_factory.cpp",
|
||||||
|
|||||||
@@ -364,7 +364,10 @@ TypeAndCreationStatus ABIWrapper::SetTypeKind(
|
|||||||
if (type_ptr->isRecordType()) {
|
if (type_ptr->isRecordType()) {
|
||||||
// If this record is anonymous, create it.
|
// If this record is anonymous, create it.
|
||||||
const clang::RecordDecl *anon_record = GetAnonymousRecord(canonical_type);
|
const clang::RecordDecl *anon_record = GetAnonymousRecord(canonical_type);
|
||||||
if (anon_record && !CreateAnonymousRecord(anon_record)) {
|
// Avoid constructing RecordDeclWrapper with invalid record, which results
|
||||||
|
// in segmentation fault.
|
||||||
|
if (anon_record && !anon_record->isInvalidDecl() &&
|
||||||
|
!CreateAnonymousRecord(anon_record)) {
|
||||||
llvm::errs() << "Anonymous record could not be created\n";
|
llvm::errs() << "Anonymous record could not be created\n";
|
||||||
::exit(1);
|
::exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,12 @@ bool HeaderASTVisitor::ShouldSkipFunctionDecl(const clang::FunctionDecl *decl) {
|
|||||||
}
|
}
|
||||||
if (const clang::CXXMethodDecl *method_decl =
|
if (const clang::CXXMethodDecl *method_decl =
|
||||||
llvm::dyn_cast<clang::CXXMethodDecl>(decl)) {
|
llvm::dyn_cast<clang::CXXMethodDecl>(decl)) {
|
||||||
if (method_decl->getParent()->getTypeForDecl()->isDependentType()) {
|
const clang::CXXRecordDecl *record_decl = method_decl->getParent();
|
||||||
|
// Avoid segmentation fault in getThunkInfo in getAllManglings.
|
||||||
|
if (method_decl->isVirtual() && record_decl->isInvalidDecl()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (record_decl->getTypeForDecl()->isDependentType()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
// Copyright (C) 2018 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "fake_decl_source.h"
|
||||||
|
|
||||||
|
#include <clang/Lex/Lexer.h>
|
||||||
|
#include <clang/Sema/Lookup.h>
|
||||||
|
|
||||||
|
FakeDeclSource::FakeDeclSource(const clang::CompilerInstance &ci) : ci_(ci) {}
|
||||||
|
|
||||||
|
clang::CXXRecordDecl *
|
||||||
|
FakeDeclSource::CreateCXXRecordDecl(const clang::DeclarationName &name,
|
||||||
|
clang::DeclContext *decl_context) {
|
||||||
|
clang::CXXRecordDecl *cxx_record_decl = clang::CXXRecordDecl::Create(
|
||||||
|
ci_.getASTContext(), clang::TTK_Struct, decl_context,
|
||||||
|
clang::SourceLocation(), clang::SourceLocation(),
|
||||||
|
name.getAsIdentifierInfo(), /* PrevDecl */ nullptr);
|
||||||
|
cxx_record_decl->setInvalidDecl(true);
|
||||||
|
|
||||||
|
return cxx_record_decl;
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::ClassTemplateDecl *
|
||||||
|
FakeDeclSource::CreateClassTemplateDecl(clang::CXXRecordDecl *cxx_record_decl,
|
||||||
|
clang::DeclContext *decl_context) {
|
||||||
|
clang::ASTContext &ast = ci_.getASTContext();
|
||||||
|
|
||||||
|
// Declare `template<typename ...T> struct RecordName` in decl_context.
|
||||||
|
clang::TemplateTypeParmDecl *parm = clang::TemplateTypeParmDecl::Create(
|
||||||
|
ast, decl_context, clang::SourceLocation(), clang::SourceLocation(),
|
||||||
|
/* Depth */ 0, /* Position */ 0, /* Id */ nullptr,
|
||||||
|
/* Typename */ true, /* ParameterPack */ true);
|
||||||
|
parm->setInvalidDecl(true);
|
||||||
|
|
||||||
|
clang::NamedDecl *parm_array[1] = {parm};
|
||||||
|
clang::TemplateParameterList *parm_list =
|
||||||
|
clang::TemplateParameterList::Create(
|
||||||
|
ast, clang::SourceLocation(), clang::SourceLocation(), parm_array,
|
||||||
|
clang::SourceLocation(), /* RequiresClause */ nullptr);
|
||||||
|
|
||||||
|
clang::ClassTemplateDecl *class_template_decl =
|
||||||
|
clang::ClassTemplateDecl::Create(
|
||||||
|
ast, decl_context, clang::SourceLocation(),
|
||||||
|
cxx_record_decl->getDeclName(), parm_list, cxx_record_decl,
|
||||||
|
/* AssociatedConstraints */ nullptr);
|
||||||
|
|
||||||
|
cxx_record_decl->setDescribedClassTemplate(class_template_decl);
|
||||||
|
class_template_decl->setInvalidDecl(true);
|
||||||
|
|
||||||
|
return class_template_decl;
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::NamespaceDecl *
|
||||||
|
FakeDeclSource::CreateNamespaceDecl(const clang::DeclarationName &name,
|
||||||
|
clang::DeclContext *decl_context) {
|
||||||
|
clang::NamespaceDecl *namespace_decl = clang::NamespaceDecl::Create(
|
||||||
|
ci_.getASTContext(), decl_context, /* Inline */ false,
|
||||||
|
clang::SourceLocation(), clang::SourceLocation(),
|
||||||
|
name.getAsIdentifierInfo(), /* PrevDecl */ nullptr);
|
||||||
|
namespace_decl->setInvalidDecl(true);
|
||||||
|
|
||||||
|
return namespace_decl;
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::NamedDecl *
|
||||||
|
FakeDeclSource::CreateDecl(clang::Sema::LookupNameKind kind,
|
||||||
|
const clang::DeclarationNameInfo &name_info,
|
||||||
|
clang::DeclContext *decl_context) {
|
||||||
|
const clang::DeclarationName &name = name_info.getName();
|
||||||
|
if (name.getNameKind() != clang::DeclarationName::Identifier) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::NamedDecl *decl;
|
||||||
|
switch (kind) {
|
||||||
|
case clang::Sema::LookupOrdinaryName:
|
||||||
|
case clang::Sema::LookupTagName: {
|
||||||
|
clang::CXXRecordDecl *cxx_record_decl =
|
||||||
|
CreateCXXRecordDecl(name, decl_context);
|
||||||
|
// If `<` follows the type name, the type must be a template.
|
||||||
|
// Otherwise, the compiler takes it as a syntax error.
|
||||||
|
clang::Optional<clang::Token> next_token = clang::Lexer::findNextToken(
|
||||||
|
name_info.getLoc(), ci_.getASTContext().getSourceManager(),
|
||||||
|
ci_.getLangOpts());
|
||||||
|
if (next_token.hasValue() && next_token->is(clang::tok::less)) {
|
||||||
|
decl = CreateClassTemplateDecl(cxx_record_decl, decl_context);
|
||||||
|
} else {
|
||||||
|
decl = cxx_record_decl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case clang::Sema::LookupNestedNameSpecifierName:
|
||||||
|
decl = CreateNamespaceDecl(name, decl_context);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
decl = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decl) {
|
||||||
|
decl_context->addDecl(decl);
|
||||||
|
}
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::DeclContext *
|
||||||
|
FakeDeclSource::ResolveDeclContext(clang::DeclContext *member_context,
|
||||||
|
clang::Scope *scope,
|
||||||
|
clang::NestedNameSpecifier *nns) {
|
||||||
|
if (member_context) {
|
||||||
|
return member_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nns) {
|
||||||
|
switch (nns->getKind()) {
|
||||||
|
case clang::NestedNameSpecifier::Namespace:
|
||||||
|
return nns->getAsNamespace();
|
||||||
|
case clang::NestedNameSpecifier::NamespaceAlias:
|
||||||
|
return nns->getAsNamespaceAlias()->getNamespace();
|
||||||
|
case clang::NestedNameSpecifier::TypeSpec:
|
||||||
|
case clang::NestedNameSpecifier::TypeSpecWithTemplate:
|
||||||
|
return nns->getAsRecordDecl();
|
||||||
|
case clang::NestedNameSpecifier::Global:
|
||||||
|
return ci_.getASTContext().getTranslationUnitDecl();
|
||||||
|
case clang::NestedNameSpecifier::Identifier:
|
||||||
|
case clang::NestedNameSpecifier::Super:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scope && scope->getEntity()) {
|
||||||
|
return scope->getEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ci_.getASTContext().getTranslationUnitDecl();
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::TypoCorrection FakeDeclSource::CorrectTypo(
|
||||||
|
const clang::DeclarationNameInfo &typo, int lookup_kind,
|
||||||
|
clang::Scope *scope, clang::CXXScopeSpec *scope_spec,
|
||||||
|
clang::CorrectionCandidateCallback &ccc, clang::DeclContext *member_context,
|
||||||
|
bool entering_context, const clang::ObjCObjectPointerType *opt) {
|
||||||
|
// Skip function bodies.
|
||||||
|
if (scope && scope->getFnParent()) {
|
||||||
|
return clang::TypoCorrection();
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::NestedNameSpecifier *nns = nullptr;
|
||||||
|
if (scope_spec && !scope_spec->isEmpty()) {
|
||||||
|
nns = scope_spec->getScopeRep();
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::DeclContext *decl_context =
|
||||||
|
ResolveDeclContext(member_context, scope, nns);
|
||||||
|
|
||||||
|
clang::NamedDecl *decl =
|
||||||
|
CreateDecl(clang::Sema::LookupNameKind(lookup_kind), typo, decl_context);
|
||||||
|
if (decl == nullptr) {
|
||||||
|
return clang::TypoCorrection();
|
||||||
|
}
|
||||||
|
|
||||||
|
return clang::TypoCorrection(decl, nns);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FakeDeclSource::LookupUnqualified(clang::LookupResult &result,
|
||||||
|
clang::Scope *scope) {
|
||||||
|
// The compiler looks for redeclaration when it parses a known name.
|
||||||
|
if (result.isForRedeclaration()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Skip function bodies.
|
||||||
|
if (scope && scope->getFnParent()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::DeclContext *decl_context;
|
||||||
|
if (scope && scope->getEntity()) {
|
||||||
|
decl_context = scope->getEntity();
|
||||||
|
} else {
|
||||||
|
decl_context = ci_.getASTContext().getTranslationUnitDecl();
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::NamedDecl *decl = CreateDecl(result.getLookupKind(),
|
||||||
|
result.getLookupNameInfo(), decl_context);
|
||||||
|
if (decl == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.addDecl(decl);
|
||||||
|
result.resolveKind();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (C) 2018 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <clang/Frontend/CompilerInstance.h>
|
||||||
|
#include <clang/Sema/ExternalSemaSource.h>
|
||||||
|
#include <clang/Sema/Sema.h>
|
||||||
|
|
||||||
|
// This class creates fake declarations when the compiler queries for unknown
|
||||||
|
// types.
|
||||||
|
class FakeDeclSource : public clang::ExternalSemaSource {
|
||||||
|
private:
|
||||||
|
const clang::CompilerInstance &ci_;
|
||||||
|
|
||||||
|
clang::CXXRecordDecl *CreateCXXRecordDecl(const clang::DeclarationName &name,
|
||||||
|
clang::DeclContext *decl_context);
|
||||||
|
|
||||||
|
clang::ClassTemplateDecl *
|
||||||
|
CreateClassTemplateDecl(clang::CXXRecordDecl *cxx_record_decl,
|
||||||
|
clang::DeclContext *decl_context);
|
||||||
|
|
||||||
|
clang::NamespaceDecl *CreateNamespaceDecl(const clang::DeclarationName &name,
|
||||||
|
clang::DeclContext *decl_context);
|
||||||
|
|
||||||
|
// This method creates a declaration in decl_context according to the lookup
|
||||||
|
// name kind and the declaration name kind. If this method doesn't support the
|
||||||
|
// kinds, it returns nullptr.
|
||||||
|
clang::NamedDecl *CreateDecl(clang::Sema::LookupNameKind kind,
|
||||||
|
const clang::DeclarationNameInfo &name,
|
||||||
|
clang::DeclContext *decl_context);
|
||||||
|
|
||||||
|
// Return the DeclContext for CorrectTypo to create a declaration in.
|
||||||
|
clang::DeclContext *ResolveDeclContext(clang::DeclContext *member_context,
|
||||||
|
clang::Scope *scope,
|
||||||
|
clang::NestedNameSpecifier *nns);
|
||||||
|
|
||||||
|
public:
|
||||||
|
FakeDeclSource(const clang::CompilerInstance &ci);
|
||||||
|
|
||||||
|
clang::TypoCorrection
|
||||||
|
CorrectTypo(const clang::DeclarationNameInfo &typo, int lookup_kind,
|
||||||
|
clang::Scope *scope, clang::CXXScopeSpec *scope_spec,
|
||||||
|
clang::CorrectionCandidateCallback &ccc,
|
||||||
|
clang::DeclContext *member_context, bool entering_context,
|
||||||
|
const clang::ObjCObjectPointerType *opt) override;
|
||||||
|
|
||||||
|
bool LookupUnqualified(clang::LookupResult &result,
|
||||||
|
clang::Scope *scope) override;
|
||||||
|
};
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "ast_processing.h"
|
#include "ast_processing.h"
|
||||||
#include "diagnostic_consumer.h"
|
#include "diagnostic_consumer.h"
|
||||||
|
#include "fake_decl_source.h"
|
||||||
#include "header_abi_util.h"
|
#include "header_abi_util.h"
|
||||||
#include "ir_representation.h"
|
#include "ir_representation.h"
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ HeaderCheckerFrontendAction::CreateASTConsumer(clang::CompilerInstance &ci,
|
|||||||
|
|
||||||
bool HeaderCheckerFrontendAction::BeginInvocation(clang::CompilerInstance &ci) {
|
bool HeaderCheckerFrontendAction::BeginInvocation(clang::CompilerInstance &ci) {
|
||||||
if (options_.suppress_errors_) {
|
if (options_.suppress_errors_) {
|
||||||
|
ci.getFrontendOpts().SkipFunctionBodies = true;
|
||||||
clang::DiagnosticsEngine &diagnostics = ci.getDiagnostics();
|
clang::DiagnosticsEngine &diagnostics = ci.getDiagnostics();
|
||||||
diagnostics.setClient(
|
diagnostics.setClient(
|
||||||
new HeaderCheckerDiagnosticConsumer(diagnostics.takeClient()),
|
new HeaderCheckerDiagnosticConsumer(diagnostics.takeClient()),
|
||||||
@@ -48,7 +50,9 @@ bool HeaderCheckerFrontendAction::BeginInvocation(clang::CompilerInstance &ci) {
|
|||||||
|
|
||||||
bool HeaderCheckerFrontendAction::BeginSourceFileAction(
|
bool HeaderCheckerFrontendAction::BeginSourceFileAction(
|
||||||
clang::CompilerInstance &ci) {
|
clang::CompilerInstance &ci) {
|
||||||
ci.getPreprocessor().SetSuppressIncludeNotFoundError(
|
if (options_.suppress_errors_) {
|
||||||
options_.suppress_errors_);
|
ci.setExternalSemaSource(new FakeDeclSource(ci));
|
||||||
|
ci.getPreprocessor().SetSuppressIncludeNotFoundError(true);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user