Skip to content

Commit

Permalink
Clang importer: start building a Swift name -> Clang declarations table.
Browse files Browse the repository at this point in the history
When we parse a bridging header, start building a mapping from Swift
names (both base names and full names) to the Clang declarations that
have those names in particular Clang contexts. For now, just provide
the ability to build the table (barely) and dump it out; we'll grow
it's contents in time.
  • Loading branch information
DougGregor committed Dec 3, 2015
1 parent f44f4a5 commit c2bf16c
Show file tree
Hide file tree
Showing 10 changed files with 350 additions and 3 deletions.
3 changes: 3 additions & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ class ClangImporter final : public ClangModuleLoader {
// Print statistics from the Clang AST reader.
void printStatistics() const override;

/// Dump Swift lookup tables.
void dumpSwiftLookupTables();

/// Given the path of a Clang module, collect the names of all its submodules
/// and their corresponding visibility. Calling this function does not load the
/// module.
Expand Down
4 changes: 4 additions & 0 deletions include/swift/ClangImporter/ClangImporterOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class ClangImporterOptions {
// If true, infer default arguments for nullable pointers (nil) and
// option sets ([]).
bool InferDefaultArguments = false;

/// If true, we should use the Swift name lookup tables rather than
/// Clang's name lookup facilities.
bool UseSwiftLookupTables = false;
};

} // end namespace swift
Expand Down
1 change: 1 addition & 0 deletions lib/ClangImporter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ add_swift_library(swiftClangImporter
ImportDecl.cpp
ImportMacro.cpp
ImportType.cpp
SwiftLookupTable.cpp
LINK_LIBRARIES
swiftAST
)
Expand Down
24 changes: 21 additions & 3 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,9 +736,18 @@ bool ClangImporter::Implementation::importHeader(

clang::Parser::DeclGroupPtrTy parsed;
while (!Parser->ParseTopLevelDecl(parsed)) {
if (trackParsedSymbols && parsed) {
if (parsed && (trackParsedSymbols || UseSwiftLookupTables)) {
for (auto *D : parsed.get()) {
addBridgeHeaderTopLevelDecls(D);
if (trackParsedSymbols)
addBridgeHeaderTopLevelDecls(D);

if (UseSwiftLookupTables) {
if (auto named = dyn_cast<clang::NamedDecl>(D)) {
Identifier name = importName(named);
if (!name.empty())
BridgingHeaderLookupTable.addEntry(name, named);
}
}
}
}
}
Expand Down Expand Up @@ -1021,7 +1030,8 @@ ClangImporter::Implementation::Implementation(ASTContext &ctx,
InferImplicitProperties(opts.InferImplicitProperties),
ImportForwardDeclarations(opts.ImportForwardDeclarations),
OmitNeedlessWords(opts.OmitNeedlessWords),
InferDefaultArguments(opts.InferDefaultArguments)
InferDefaultArguments(opts.InferDefaultArguments),
UseSwiftLookupTables(opts.UseSwiftLookupTables)
{
// Add filters to determine if a Clang availability attribute
// applies in Swift, and if so, what is the cutoff for deprecated
Expand Down Expand Up @@ -3306,3 +3316,11 @@ void ClangImporter::getMangledName(raw_ostream &os,

Impl.Mangler->mangleName(clangDecl, os);
}

void ClangImporter::dumpSwiftLookupTables() {
Impl.dumpSwiftLookupTables();
}

void ClangImporter::Implementation::dumpSwiftLookupTables() {
BridgingHeaderLookupTable.dump();
}
8 changes: 8 additions & 0 deletions lib/ClangImporter/ImporterImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef SWIFT_CLANG_IMPORTER_IMPL_H
#define SWIFT_CLANG_IMPORTER_IMPL_H

#include "SwiftLookupTable.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/LazyResolver.h"
Expand Down Expand Up @@ -251,6 +252,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
const bool ImportForwardDeclarations;
const bool OmitNeedlessWords;
const bool InferDefaultArguments;
const bool UseSwiftLookupTables;

constexpr static const char * const moduleImportBufferName =
"<swift-imported-modules>";
Expand Down Expand Up @@ -289,6 +291,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
/// if type checking has begun.
llvm::PointerIntPair<LazyResolver *, 1, bool> typeResolver;

/// The Swift lookup table for the bridging header.
SwiftLookupTable BridgingHeaderLookupTable;

public:
/// \brief Mapping of already-imported declarations.
llvm::DenseMap<const clang::Decl *, Decl *> ImportedDecls;
Expand Down Expand Up @@ -1177,6 +1182,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
ASD->setSetterAccessibility(Accessibility::Public);
return D;
}

/// Dump the Swift-specific name lookup tables we generate.
void dumpSwiftLookupTables();
};

}
Expand Down
139 changes: 139 additions & 0 deletions lib/ClangImporter/SwiftLookupTable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
//===--- SwiftLookupTable.cpp - Swift Lookup Table ------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements support for Swift name lookup tables stored in Clang
// modules.
//
//===----------------------------------------------------------------------===//
#include "SwiftLookupTable.h"
#include "swift/Basic/STLExtras.h"
#include "clang/AST/DeclObjC.h"
using namespace swift;

bool SwiftLookupTable::matchesContext(clang::DeclContext *foundContext,
clang::DeclContext *requestedContext) {
/// If the requested context was null, we match.
if (!requestedContext)
return true;

// If the contexts match, we match.
if (foundContext == requestedContext)
return true;

// If we found something in an Objective-C protocol to which a class
// conforms, we match.
if (auto objcProto = dyn_cast<clang::ObjCProtocolDecl>(foundContext)) {
if (auto objcClass = dyn_cast<clang::ObjCInterfaceDecl>(requestedContext)) {
return objcClass->ClassImplementsProtocol(objcProto,
/*lookupCategory=*/true);
}
}

return false;
}

void SwiftLookupTable::addEntry(DeclName name, clang::NamedDecl *decl) {
clang::DeclContext *context
= decl->getDeclContext()->getRedeclContext()->getPrimaryContext();

// First, check whether there is already a full name entry.
auto knownFull = FullNameTable.find(name);
if (knownFull == FullNameTable.end()) {
// We didn't have a full name entry, so record that in the base
// name table.
BaseNameTable[name.getBaseName()].push_back(name);

// Insert the entry into the full name table. We're done.
FullTableEntry newEntry;
newEntry.Context = context;
newEntry.Decls.push_back(decl);
(void)FullNameTable.insert({name, { newEntry }});
return;
}

// Check whether there is already an entry with the same context.
auto &fullEntries = knownFull->second;
for (auto &fullEntry : fullEntries) {
if (fullEntry.Context == context) {
fullEntry.Decls.push_back(decl);
return;
}
}

// This is a new context for this name. Add it.
FullTableEntry newEntry;
newEntry.Context = context;
newEntry.Decls.push_back(decl);
fullEntries.push_back(newEntry);
}

void SwiftLookupTable::dump() const {
// Dump the base name -> full name mappings.
SmallVector<Identifier, 4> baseNames;
for (const auto &entry : BaseNameTable) {
baseNames.push_back(entry.first);
}
std::sort(baseNames.begin(), baseNames.end(),
[&](Identifier x, Identifier y) {
return x.compare(y) < 0;
});
llvm::errs() << "Base -> full name mappings:\n";
for (auto baseName : baseNames) {
llvm::errs() << " " << baseName.str() << " --> ";
const auto &fullNames = BaseNameTable.find(baseName)->second;
interleave(fullNames.begin(), fullNames.end(),
[](DeclName fullName) {
llvm::errs() << fullName;
},
[] {
llvm::errs() << ", ";
});
llvm::errs() << "\n";
}
llvm::errs() << "\n";

// Dump the full name -> full table entry mappings.
SmallVector<DeclName, 4> fullNames;
for (const auto &entry : FullNameTable) {
fullNames.push_back(entry.first);
}
std::sort(fullNames.begin(), fullNames.end(),
[](DeclName x, DeclName y) {
return x.compare(y) < 0;
});
llvm::errs() << "Full name -> entry mappings:\n";
for (auto fullName : fullNames) {
llvm::errs() << " " << fullName << ":\n";
const auto &fullEntries = FullNameTable.find(fullName)->second;
for (const auto &fullEntry : fullEntries) {
llvm::errs() << " ";
if (fullEntry.Context->isTranslationUnit()) {
llvm::errs() << "TU";
} else if (auto named = dyn_cast<clang::NamedDecl>(fullEntry.Context)) {
named->printName(llvm::errs());
llvm::errs();
} else {
llvm::errs() << "<unknown>";
}
llvm::errs() << ": ";

interleave(fullEntry.Decls.begin(), fullEntry.Decls.end(),
[](clang::NamedDecl *decl) {
decl->printName(llvm::errs());
},
[] {
llvm::errs() << ", ";
});
llvm::errs() << "\n";
}
}
}
108 changes: 108 additions & 0 deletions lib/ClangImporter/SwiftLookupTable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//===--- SwiftLookupTable.h - Swift Lookup Table ----------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements support for Swift name lookup tables stored in Clang
// modules.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H
#define SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H

#include "swift/Basic/LLVM.h"
#include "swift/AST/Identifier.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TinyPtrVector.h"

namespace clang {
class NamedDecl;
class DeclContext;
}

namespace swift {

/// A lookup table that maps Swift names to the set of Clang
/// declarations with that particular name.
///
/// The names of C entities can undergo significant transformations
/// when they are mapped into Swift, which makes Clang's name lookup
/// mechanisms useless when searching for the Swift name of
/// entities. This lookup table provides efficient access to the C
/// entities based on their Swift names, and is used by the Clang
/// importer to satisfy the Swift compiler's queries.
class SwiftLookupTable {
/// An entry in the table of C entities indexed by full Swift name.
struct FullTableEntry {
/// The context in which the entities with the given name occur, e.g.,
/// a class, struct, translation unit, etc.
///
/// Many Clang DeclContexts can have redeclarations, so this entry
/// is always the canonical DeclContext for the entity.
clang::DeclContext *Context;

/// The set of Clang declarations with this name and in this
/// context.
llvm::TinyPtrVector<clang::NamedDecl *> Decls;
};

/// A table mapping from the full name of Swift entities to all of
/// the C entities that have that name, in all contexts.
llvm::DenseMap<DeclName, SmallVector<FullTableEntry, 2>> FullNameTable;

/// A table mapping from the base name of a Swift name to all of the
/// full Swift names based on that identifier.
llvm::DenseMap<Identifier, SmallVector<DeclName, 2>> BaseNameTable;

/// Determine whether the given context we found matches the
/// requested context.
bool matchesContext(clang::DeclContext *foundContext,
clang::DeclContext *requestedContext);
public:
/// Add an entry to the lookup table.
///
/// \param name The Swift name of the entry.
/// \param decl The Clang declaration to add.
void addEntry(DeclName name, clang::NamedDecl *decl);

/// Lookup the set of declarations with the given base name.
///
/// \param baseName The base name to search for. All results will
/// have this base name.
///
/// \param context The context in which the resulting set of
/// declarations should reside. This may be null to indicate that
/// all results from all contexts should be produced.
ArrayRef<clang::NamedDecl *>
lookup(Identifier baseName,
clang::DeclContext *context,
SmallVectorImpl<clang::NamedDecl *> &scratch);

/// Lookup the set of declarations with the given full name.
///
/// \param name The full name to search for. All results will have
/// this full name.
///
/// \param context The context in which the resulting set of
/// declarations should reside. This may be null to indicate that
/// all results from all contexts should be produced.
ArrayRef<clang::NamedDecl *>
lookup(DeclName name,
clang::DeclContext *context,
SmallVectorImpl<clang::NamedDecl *> &scratch);

/// Dump the internal representation of this lookup table.
void dump() const;
};

}

#endif // SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H
7 changes: 7 additions & 0 deletions test/IDE/Inputs/swift_name.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#define SWIFT_NAME(X) __attribute__((swift_name(#X)))

int SNFoo SWIFT_NAME(Bar);

struct SWIFT_NAME(SomeStruct) SNSomeStruct {
double X SWIFT_NAME(x);
};
12 changes: 12 additions & 0 deletions test/IDE/dump_swift_lookup_tables.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %target-swift-ide-test -dump-importer-lookup-table -source-filename %s -import-objc-header %S/Inputs/swift_name.h > %t.log 2>&1
// RUN: FileCheck %s < %t.log

// CHECK: Base -> full name mappings:
// CHECK-NEXT: Bar --> Bar
// CHECK-NEXT: SomeStruct --> SomeStruct

// CHECK: Full name -> entry mappings:
// CHECK-NEXT: Bar:
// CHECK-NEXT: TU: SNFoo
// CHECK-NEXT: SomeStruct:
// CHECK-NEXT: TU: SNSomeStruct
Loading

0 comments on commit c2bf16c

Please sign in to comment.