Skip to content

Commit

Permalink
Merge pull request swiftlang#27924 from jrose-apple/attribute-attribu…
Browse files Browse the repository at this point in the history
…tion

[ClangImporter] Diagnose bad swift_name attributes better
  • Loading branch information
jrose-apple authored Oct 30, 2019
2 parents 5f3b1da + efa82fc commit 37bb356
Show file tree
Hide file tree
Showing 15 changed files with 259 additions and 126 deletions.
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsClangImporter.def
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ WARNING(unresolvable_clang_decl,none,
"imported declaration '%0' could not be mapped to '%1'",
(StringRef, StringRef))

NOTE(unresolvable_clang_decl_is_a_framework_bug,none,
"please report this issue to the owners of '%0'",
(StringRef))

WARNING(implicit_bridging_header_imported_from_module,none,
"implicit import of bridging header '%0' via module %1 "
"is deprecated and will be removed in a later version of 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 @@ -9,6 +9,7 @@ add_swift_host_library(swiftClangImporter STATIC
ClangAdapter.cpp
ClangDiagnosticConsumer.cpp
ClangImporter.cpp
ClangSourceBufferImporter.cpp
DWARFImporter.cpp
IAMInference.cpp
ImportDecl.cpp
Expand Down
97 changes: 14 additions & 83 deletions lib/ClangImporter/ClangDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "ClangDiagnosticConsumer.h"
#include "ClangSourceBufferImporter.h"
#include "ImporterImpl.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticEngine.h"
Expand All @@ -22,6 +23,7 @@
#include "llvm/ADT/STLExtras.h"

using namespace swift;
using namespace swift::importer;

namespace {
class ClangDiagRenderer final : public clang::DiagnosticNoteRenderer {
Expand Down Expand Up @@ -109,81 +111,6 @@ ClangDiagnosticConsumer::ClangDiagnosticConsumer(
: TextDiagnosticPrinter(llvm::errs(), &clangDiagOptions),
ImporterImpl(impl), DumpToStderr(dumpToStderr) {}

static SourceLoc findEndOfLine(SourceManager &SM, SourceLoc loc,
unsigned bufferID) {
CharSourceRange entireBuffer = SM.getRangeForBuffer(bufferID);
CharSourceRange rangeFromLoc{SM, loc, entireBuffer.getEnd()};
StringRef textFromLoc = SM.extractText(rangeFromLoc);
size_t newlineOffset = textFromLoc.find_first_of({"\r\n\0", 3});
if (newlineOffset == StringRef::npos)
return entireBuffer.getEnd();
return loc.getAdvancedLoc(newlineOffset);
}

SourceLoc ClangDiagnosticConsumer::resolveSourceLocation(
const clang::SourceManager &clangSrcMgr,
clang::SourceLocation clangLoc) {
SourceManager &swiftSrcMgr = ImporterImpl.SwiftContext.SourceMgr;
SourceLoc loc;

clangLoc = clangSrcMgr.getFileLoc(clangLoc);
auto decomposedLoc = clangSrcMgr.getDecomposedLoc(clangLoc);
if (decomposedLoc.first.isInvalid())
return loc;

auto buffer = clangSrcMgr.getBuffer(decomposedLoc.first);
unsigned mirrorID;

auto mirrorIter = mirroredBuffers.find(buffer);
if (mirrorIter != mirroredBuffers.end()) {
mirrorID = mirrorIter->second;
} else {
std::unique_ptr<llvm::MemoryBuffer> mirrorBuffer{
llvm::MemoryBuffer::getMemBuffer(buffer->getBuffer(),
buffer->getBufferIdentifier(),
/*RequiresNullTerminator=*/true)
};
mirrorID = swiftSrcMgr.addNewSourceBuffer(std::move(mirrorBuffer));
mirroredBuffers[buffer] = mirrorID;
}
loc = swiftSrcMgr.getLocForOffset(mirrorID, decomposedLoc.second);

auto presumedLoc = clangSrcMgr.getPresumedLoc(clangLoc);
if (!presumedLoc.getFilename())
return loc;
if (presumedLoc.getLine() == 0)
return SourceLoc();

unsigned bufferLineNumber =
clangSrcMgr.getLineNumber(decomposedLoc.first, decomposedLoc.second);

StringRef presumedFile = presumedLoc.getFilename();
SourceLoc startOfLine = loc.getAdvancedLoc(-presumedLoc.getColumn() + 1);
bool isNewVirtualFile =
swiftSrcMgr.openVirtualFile(startOfLine, presumedFile,
presumedLoc.getLine() - bufferLineNumber);
if (isNewVirtualFile) {
SourceLoc endOfLine = findEndOfLine(swiftSrcMgr, loc, mirrorID);
swiftSrcMgr.closeVirtualFile(endOfLine);
}

using SourceManagerRef = llvm::IntrusiveRefCntPtr<const clang::SourceManager>;
auto iter = std::lower_bound(sourceManagersWithDiagnostics.begin(),
sourceManagersWithDiagnostics.end(),
&clangSrcMgr,
[](const SourceManagerRef &inArray,
const clang::SourceManager *toInsert) {
return std::less<const clang::SourceManager *>()(inArray.get(), toInsert);
});
if (iter == sourceManagersWithDiagnostics.end() ||
iter->get() != &clangSrcMgr) {
sourceManagersWithDiagnostics.insert(iter, &clangSrcMgr);
}

return loc;
}


void ClangDiagnosticConsumer::HandleDiagnostic(
clang::DiagnosticsEngine::Level clangDiagLevel,
const clang::Diagnostic &clangDiag) {
Expand All @@ -195,13 +122,16 @@ void ClangDiagnosticConsumer::HandleDiagnostic(
}

const ASTContext &ctx = ImporterImpl.SwiftContext;
ClangSourceBufferImporter &bufferImporter =
ImporterImpl.getBufferImporterForDiagnostics();

if (clangDiag.getID() == clang::diag::err_module_not_built &&
CurrentImport && clangDiag.getArgStdStr(0) == CurrentImport->getName()) {
SourceLoc loc = DiagLoc;
if (clangDiag.getLocation().isValid())
loc = resolveSourceLocation(clangDiag.getSourceManager(),
clangDiag.getLocation());
if (clangDiag.getLocation().isValid()) {
loc = bufferImporter.resolveSourceLocation(clangDiag.getSourceManager(),
clangDiag.getLocation());
}

ctx.Diags.diagnose(loc, diag::clang_cannot_build_module,
ctx.LangOpts.EnableObjCInterop,
Expand All @@ -216,9 +146,10 @@ void ClangDiagnosticConsumer::HandleDiagnostic(
DiagnosticConsumer::HandleDiagnostic(clangDiagLevel, clangDiag);

// FIXME: Map over source ranges in the diagnostic.
auto emitDiag = [&ctx, this](clang::FullSourceLoc clangNoteLoc,
clang::DiagnosticsEngine::Level clangDiagLevel,
StringRef message) {
auto emitDiag =
[&ctx, &bufferImporter](clang::FullSourceLoc clangNoteLoc,
clang::DiagnosticsEngine::Level clangDiagLevel,
StringRef message) {
decltype(diag::error_from_clang) diagKind;
switch (clangDiagLevel) {
case clang::DiagnosticsEngine::Ignored:
Expand All @@ -241,8 +172,8 @@ void ClangDiagnosticConsumer::HandleDiagnostic(

SourceLoc noteLoc;
if (clangNoteLoc.isValid())
noteLoc = resolveSourceLocation(clangNoteLoc.getManager(),
clangNoteLoc);
noteLoc = bufferImporter.resolveSourceLocation(clangNoteLoc.getManager(),
clangNoteLoc);
ctx.Diags.diagnose(noteLoc, diagKind, message);
};

Expand Down
18 changes: 0 additions & 18 deletions lib/ClangImporter/ClangDiagnosticConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,6 @@ class ClangDiagnosticConsumer : public clang::TextDiagnosticPrinter {

ClangImporter::Implementation &ImporterImpl;

/// Keeps alive the Clang source managers where diagnostics have been
/// reported.
///
/// This is a bit of a hack, but LLVM's source manager (and by extension
/// Swift's) does not support buffers going away.
//
// This is not using SmallPtrSet or similar because we need the
// IntrusiveRefCntPtr to stay a ref-counting pointer.
SmallVector<llvm::IntrusiveRefCntPtr<const clang::SourceManager>, 4>
sourceManagersWithDiagnostics;
llvm::DenseMap<const llvm::MemoryBuffer *, unsigned> mirroredBuffers;

const clang::IdentifierInfo *CurrentImport = nullptr;
SourceLoc DiagLoc;
const bool DumpToStderr;
Expand All @@ -82,12 +70,6 @@ class ClangDiagnosticConsumer : public clang::TextDiagnosticPrinter {
return LoadModuleRAII(*this, name);
}

/// Returns a Swift source location that points into a Clang buffer.
///
/// This will keep the Clang buffer alive as long as this diagnostic consumer.
SourceLoc resolveSourceLocation(const clang::SourceManager &clangSrcMgr,
clang::SourceLocation clangLoc);

void HandleDiagnostic(clang::DiagnosticsEngine::Level diagLevel,
const clang::Diagnostic &info) override;
};
Expand Down
5 changes: 4 additions & 1 deletion lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,7 @@ ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts,
std::make_shared<SwiftNameLookupExtension>(
importer->Impl.BridgingHeaderLookupTable,
importer->Impl.LookupTables, importer->Impl.SwiftContext,
importer->Impl.getBufferImporterForDiagnostics(),
importer->Impl.platformAvailability,
importer->Impl.InferImportAsMember));

Expand Down Expand Up @@ -1330,7 +1331,8 @@ bool ClangImporter::Implementation::importHeader(
}

// Finalize the lookup table, which may fail.
finalizeLookupTable(*BridgingHeaderLookupTable, getNameImporter());
finalizeLookupTable(*BridgingHeaderLookupTable, getNameImporter(),
getBufferImporterForDiagnostics());

// FIXME: What do we do if there was already an error?
if (!hadError && clangDiags.hasErrorOccurred()) {
Expand Down Expand Up @@ -1852,6 +1854,7 @@ ClangImporter::Implementation::Implementation(
IsReadingBridgingPCH(false),
CurrentVersion(ImportNameVersion::fromOptions(ctx.LangOpts)),
BridgingHeaderLookupTable(new SwiftLookupTable(nullptr)),
BuffersForDiagnostics(ctx.SourceMgr),
platformAvailability(ctx.LangOpts), nameImporter(),
DWARFImporter(dwarfImporterDelegate) {}

Expand Down
91 changes: 91 additions & 0 deletions lib/ClangImporter/ClangSourceBufferImporter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//===--- ClangSourceBufferImporter.cpp - Map Clang buffers to Swift -------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#import "ClangSourceBufferImporter.h"
#import "swift/Basic/SourceManager.h"
#import "clang/Basic/SourceManager.h"
#import "llvm/Support/MemoryBuffer.h"

using namespace swift;
using namespace swift::importer;

static SourceLoc findEndOfLine(SourceManager &SM, SourceLoc loc,
unsigned bufferID) {
CharSourceRange entireBuffer = SM.getRangeForBuffer(bufferID);
CharSourceRange rangeFromLoc{SM, loc, entireBuffer.getEnd()};
StringRef textFromLoc = SM.extractText(rangeFromLoc);
size_t newlineOffset = textFromLoc.find_first_of({"\r\n\0", 3});
if (newlineOffset == StringRef::npos)
return entireBuffer.getEnd();
return loc.getAdvancedLoc(newlineOffset);
}

SourceLoc ClangSourceBufferImporter::resolveSourceLocation(
const clang::SourceManager &clangSrcMgr,
clang::SourceLocation clangLoc) {
SourceLoc loc;

clangLoc = clangSrcMgr.getFileLoc(clangLoc);
auto decomposedLoc = clangSrcMgr.getDecomposedLoc(clangLoc);
if (decomposedLoc.first.isInvalid())
return loc;

auto buffer = clangSrcMgr.getBuffer(decomposedLoc.first);
unsigned mirrorID;

auto mirrorIter = mirroredBuffers.find(buffer);
if (mirrorIter != mirroredBuffers.end()) {
mirrorID = mirrorIter->second;
} else {
std::unique_ptr<llvm::MemoryBuffer> mirrorBuffer{
llvm::MemoryBuffer::getMemBuffer(buffer->getBuffer(),
buffer->getBufferIdentifier(),
/*RequiresNullTerminator=*/true)
};
mirrorID = swiftSourceManager.addNewSourceBuffer(std::move(mirrorBuffer));
mirroredBuffers[buffer] = mirrorID;
}
loc = swiftSourceManager.getLocForOffset(mirrorID, decomposedLoc.second);

auto presumedLoc = clangSrcMgr.getPresumedLoc(clangLoc);
if (!presumedLoc.getFilename())
return loc;
if (presumedLoc.getLine() == 0)
return SourceLoc();

unsigned bufferLineNumber =
clangSrcMgr.getLineNumber(decomposedLoc.first, decomposedLoc.second);

StringRef presumedFile = presumedLoc.getFilename();
SourceLoc startOfLine = loc.getAdvancedLoc(-presumedLoc.getColumn() + 1);
bool isNewVirtualFile = swiftSourceManager.openVirtualFile(
startOfLine, presumedFile, presumedLoc.getLine() - bufferLineNumber);
if (isNewVirtualFile) {
SourceLoc endOfLine = findEndOfLine(swiftSourceManager, loc, mirrorID);
swiftSourceManager.closeVirtualFile(endOfLine);
}

using SourceManagerRef = llvm::IntrusiveRefCntPtr<const clang::SourceManager>;
auto iter = std::lower_bound(sourceManagersWithDiagnostics.begin(),
sourceManagersWithDiagnostics.end(),
&clangSrcMgr,
[](const SourceManagerRef &inArray,
const clang::SourceManager *toInsert) {
return std::less<const clang::SourceManager *>()(inArray.get(), toInsert);
});
if (iter == sourceManagersWithDiagnostics.end() ||
iter->get() != &clangSrcMgr) {
sourceManagersWithDiagnostics.insert(iter, &clangSrcMgr);
}

return loc;
}
64 changes: 64 additions & 0 deletions lib/ClangImporter/ClangSourceBufferImporter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===--- ClangSourceBufferImporter.h - Map Clang buffers over ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_CLANGIMPORTER_CLANGSOURCEBUFFERIMPORTER_H
#define SWIFT_CLANGIMPORTER_CLANGSOURCEBUFFERIMPORTER_H

#include "swift/Basic/LLVM.h"
#include "swift/Basic/SourceLoc.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"

namespace llvm {
class MemoryBuffer;
}

namespace clang {
class SourceManager;
}

namespace swift {
class SourceManager;

namespace importer {

/// A helper class used to keep alive the Clang source managers where
/// diagnostics have been reported.
///
/// This is a bit of a hack, but LLVM's source manager (and by extension
/// Swift's) does not support buffers going away, so if we want to report
/// diagnostics in them we have to do it this way.
class ClangSourceBufferImporter {
// This is not using SmallPtrSet or similar because we need the
// IntrusiveRefCntPtr to stay a ref-counting pointer.
SmallVector<llvm::IntrusiveRefCntPtr<const clang::SourceManager>, 4>
sourceManagersWithDiagnostics;
llvm::DenseMap<const llvm::MemoryBuffer *, unsigned> mirroredBuffers;
SourceManager &swiftSourceManager;

public:
explicit ClangSourceBufferImporter(SourceManager &sourceMgr)
: swiftSourceManager(sourceMgr) {}

/// Returns a Swift source location that points into a Clang buffer.
///
/// This will keep the Clang buffer alive as long as this object.
SourceLoc resolveSourceLocation(const clang::SourceManager &clangSrcMgr,
clang::SourceLocation clangLoc);
};

} // end namespace importer
} // end namespace swift

#endif
Loading

0 comments on commit 37bb356

Please sign in to comment.