Commit 0a146261 authored by Jacob Potter's avatar Jacob Potter

Add workaround for LWG-2148; make objc source files always include their header

parent 0832f814
......@@ -4,6 +4,7 @@
#import "TXSSortItemsCppProxy+Private.h"
#import "DJIError.h"
#import "TXSItemList+Private.h"
#import "TXSSortItems.h"
#import "TXSSortItemsCppProxy+Private.h"
#import "TXSTextboxListenerObjcProxy+Private.h"
#include <exception>
......
......@@ -3,6 +3,7 @@
#import "TXSTextboxListenerObjcProxy+Private.h"
#import "TXSItemList+Private.h"
#import "TXSTextboxListener.h"
namespace djinni_generated
{
......
......@@ -27,7 +27,8 @@ import scala.collection.mutable
class CppGenerator(spec: Spec) extends Generator(spec) {
val writeCppFile = writeCppFileGeneric(spec.cppOutFolder.get, spec.cppNamespace, spec.cppFileIdentStyle, spec.cppIncludePrefix) _
val writeHppFile = writeHppFileGeneric(spec.cppHeaderOutFolder.get, spec.cppNamespace, spec.cppFileIdentStyle) _
def writeHppFile(name: String, origin: String, includes: Iterable[String], fwds: Iterable[String], f: IndentWriter => Unit, f2: IndentWriter => Unit = (w => {})) =
writeHppFileGeneric(spec.cppHeaderOutFolder.get, spec.cppNamespace, spec.cppFileIdentStyle)(name, origin, includes, fwds, f, f2)
class CppRefs(name: String) {
var hpp = mutable.TreeSet[String]()
......@@ -83,6 +84,10 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
val refs = new CppRefs(ident.name)
val self = idCpp.enumType(ident)
if (spec.cppEnumHashWorkaround) {
refs.hpp.add("#include <functional>") // needed for std::hash
}
writeHppFile(ident, origin, refs.hpp, refs.hppFwds, w => {
w.w(s"enum class $self : int").bracedSemi {
for (o <- e.options) {
......@@ -90,6 +95,23 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
w.wl(idCpp.enum(o.ident.name) + ",")
}
}
},
w => {
// std::hash specialization has to go *outside* of the wrapNs
if (spec.cppEnumHashWorkaround) {
val fqSelf = withNs(spec.cppNamespace, self)
w.wl
wrapNamespace(w, Some("std"),
(w: IndentWriter) => {
w.wl("template <>")
w.w(s"struct hash<$fqSelf>").bracedSemi {
w.w(s"size_t operator()($fqSelf type) const").braced {
w.wl("return std::hash<int>()(static_cast<int>(type));")
}
}
}
)
}
})
}
......
......@@ -29,7 +29,8 @@ class JNIGenerator(spec: Spec) extends Generator(spec) {
val jniBaseLibFileIdentStyle = jniBaseLibClassIdentStyle
val writeJniCppFile = writeCppFileGeneric(spec.jniOutFolder.get, Some(spec.jniNamespace), spec.jniFileIdentStyle, spec.jniIncludePrefix) _
val writeJniHppFile = writeHppFileGeneric(spec.jniHeaderOutFolder.get, Some(spec.jniNamespace), spec.jniFileIdentStyle) _
def writeJniHppFile(name: String, origin: String, includes: Iterable[String], fwds: Iterable[String], f: IndentWriter => Unit, f2: IndentWriter => Unit = (w => {})) =
writeHppFileGeneric(spec.jniHeaderOutFolder.get, Some(spec.jniNamespace), spec.jniFileIdentStyle)(name, origin, includes, fwds, f, f2)
class JNIRefs(name: String) {
var jniHpp = mutable.TreeSet[String]()
......
......@@ -30,6 +30,7 @@ object Main {
var cppFileIdentStyle: IdentConverter = IdentStyle.underLower
var cppOptionalTemplate: String = "std::optional"
var cppOptionalHeader: String = "<optional>"
var cppEnumHashWorkaround : Boolean = true
var javaOutFolder: Option[File] = None
var javaPackage: Option[String] = None
var javaCppException: Option[String] = None
......@@ -100,6 +101,8 @@ object Main {
.text("The template to use for optional values (default: \"std::optional\")")
opt[String]("cpp-optional-header").valueName("<header>").foreach(x => cppOptionalHeader = x)
.text("The header to use for optional values (default: \"<optional>\")")
opt[Boolean]("cpp-enum-hash-workaround").valueName("<true/false>").foreach(x => cppEnumHashWorkaround = x)
.text("Work around LWG-2148 by generating std::hash specializations for C++ enums (default: true)")
note("")
opt[File]("jni-out").valueName("<out-folder>").foreach(x => jniOutFolder = Some(x))
.text("The folder for the JNI C++ output files (Generator disabled if unspecified).")
......@@ -205,6 +208,7 @@ object Main {
cppFileIdentStyle,
cppOptionalTemplate,
cppOptionalHeader,
cppEnumHashWorkaround,
jniOutFolder,
jniHeaderOutFolder,
jniIncludePrefix,
......
......@@ -110,7 +110,7 @@ class ObjcGenerator(spec: Spec) extends Generator(spec) {
w.wl
w.wl(s"+ ($cppSelf)objc${name}ToCpp${name}:($self)${argName}")
w.braced {
w.wl(s"return static_cast<$cppSelf>($argName);")
w.wl(s"return static_cast<enum $cppSelf>($argName);")
}
w.wl
w.wl("@end")
......@@ -215,6 +215,8 @@ class ObjcGenerator(spec: Spec) extends Generator(spec) {
w.wl("@end")
})
refs.body.add("#import " + q(headerName(ident)))
if (i.consts.nonEmpty) {
writeObjcFile(bodyName(ident.name), origin, refs.body, w => {
generateObjcConstants(w, i.consts, self)
......
......@@ -41,6 +41,7 @@ package object generatorTools {
cppFileIdentStyle: IdentConverter,
cppOptionalTemplate: String,
cppOptionalHeader: String,
cppEnumHashWorkaround: Boolean,
jniOutFolder: Option[File],
jniHeaderOutFolder: Option[File],
jniIncludePrefix: String,
......@@ -219,7 +220,7 @@ abstract class Generator(spec: Spec)
}
}
def writeHppFileGeneric(folder: File, namespace: Option[String], fileIdentStyle: IdentConverter)(name: String, origin: String, includes: Iterable[String], fwds: Iterable[String], f: IndentWriter => Unit) {
def writeHppFileGeneric(folder: File, namespace: Option[String], fileIdentStyle: IdentConverter)(name: String, origin: String, includes: Iterable[String], fwds: Iterable[String], f: IndentWriter => Unit, f2: IndentWriter => Unit) {
createFile(folder, fileIdentStyle(name) + "." + spec.cppHeaderExt, (w: IndentWriter) => {
w.wl("// AUTOGENERATED FILE - DO NOT MODIFY!")
w.wl("// This file generated by Djinni from " + origin)
......@@ -239,6 +240,7 @@ abstract class Generator(spec: Spec)
f(w)
}
)
f2(w)
})
}
......
......@@ -5,4 +5,5 @@
@import "primitive_list.djinni"
@import "exception.djinni"
@import "client_interface.djinni"
@import "enum.djinni"
@import "test.djinni"
......@@ -18,5 +18,7 @@ test_helpers = interface +c {
static check_client_interface_ascii(i: client_interface);
static check_client_interface_nonascii(i: client_interface);
static check_enum_map(m: map<color, string>);
static return_none(): optional<i32>;
}
......@@ -3,6 +3,7 @@
#pragma once
#include "color.hpp"
#include "map_list_record.hpp"
#include "nested_collection.hpp"
#include "primitive_list.hpp"
......@@ -47,5 +48,7 @@ public:
static void check_client_interface_nonascii(const std::shared_ptr<ClientInterface> & i);
static void check_enum_map(const std::unordered_map<color, std::string> & m);
static std::experimental::optional<int32_t> return_none();
};
......@@ -35,6 +35,8 @@ public abstract class TestHelpers {
public static native void checkClientInterfaceNonascii(ClientInterface i);
public static native void checkEnumMap(HashMap<Color, String> m);
public static native Integer returnNone();
public static final class NativeProxy extends TestHelpers
......
......@@ -9,6 +9,7 @@
#include "HOptional.hpp"
#include "HString.hpp"
#include "NativeClientInterface.hpp"
#include "NativeColor.hpp"
#include "NativeMapListRecord.hpp"
#include "NativeNestedCollection.hpp"
#include "NativePrimitiveList.hpp"
......@@ -194,6 +195,17 @@ CJNIEXPORT void JNICALL Java_com_dropbox_djinni_test_TestHelpers_checkClientInte
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
}
CJNIEXPORT void JNICALL Java_com_dropbox_djinni_test_TestHelpers_checkEnumMap(JNIEnv* jniEnv, jobject /*this*/, jobject j_m)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
std::unordered_map<color, std::string> c_m = ::djinni::HMap<NativeColor, ::djinni::HString>::fromJava(jniEnv, j_m);
jniEnv->DeleteLocalRef(j_m);
TestHelpers::check_enum_map(c_m);
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
}
CJNIEXPORT jobject JNICALL Java_com_dropbox_djinni_test_TestHelpers_returnNone(JNIEnv* jniEnv, jobject /*this*/)
{
try {
......
......@@ -2,6 +2,7 @@
// This file generated by Djinni from client_interface.djinni
#import "DBClientInterfaceObjcProxy+Private.h"
#import "DBClientInterface.h"
#import "DBClientReturnedRecord+Private.h"
namespace djinni_generated
......
......@@ -2,6 +2,7 @@
// This file generated by Djinni from exception.djinni
#import "DBCppExceptionCppProxy+Private.h"
#import "DBCppException.h"
#import "DBCppExceptionCppProxy+Private.h"
#import "DJIError.h"
#include <exception>
......
......@@ -2,6 +2,7 @@
// This file generated by Djinni from test.djinni
#import "DBClientInterface.h"
#import "DBColor.h"
#import <Foundation/Foundation.h>
@class DBMapListRecord;
@class DBNestedCollection;
......@@ -39,6 +40,8 @@
+ (void)checkClientInterfaceNonascii:(id <DBClientInterface>)i;
+ (void)checkEnumMap:(NSMutableDictionary *)m;
+ (NSNumber *)returnNone;
@end
......@@ -3,10 +3,13 @@
#import "DBTestHelpersCppProxy+Private.h"
#import "DBClientInterfaceObjcProxy+Private.h"
#import "DBColor.h"
#import "DBColorTranslator+Private.h"
#import "DBMapListRecord+Private.h"
#import "DBNestedCollection+Private.h"
#import "DBPrimitiveList+Private.h"
#import "DBSetRecord+Private.h"
#import "DBTestHelpers.h"
#import "DJIError.h"
#include <exception>
#include <utility>
......@@ -175,6 +178,18 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (void)checkEnumMap:(NSMutableDictionary *)m {
try {
std::unordered_map<color, std::string> cppM;
for (id objcKey_0 in m) {
color cppKey_0 = [DBColorTranslator objcColorToCppColor:(DBColor)[objcKey_0 intValue]];
std::string cppValue_0([[m objectForKey:objcKey_0] UTF8String], [[m objectForKey:objcKey_0] lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
cppM.emplace(std::move(cppKey_0), std::move(cppValue_0));
}
TestHelpers::check_enum_map(std::move(cppM));
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (NSNumber *)returnNone {
try {
std::experimental::optional<int32_t> cppRet = TestHelpers::return_none();
......
......@@ -88,3 +88,19 @@ void TestHelpers::check_client_interface_nonascii(const std::shared_ptr<ClientIn
std::experimental::optional<int32_t> TestHelpers::return_none() {
return {};
}
void TestHelpers::check_enum_map(const std::unordered_map<color, std::string> & m) {
std::unordered_map<color, std::string> expected = {
{ color::RED, "red" },
{ color::ORANGE, "orange" },
{ color::YELLOW, "yellow" },
{ color::GREEN, "green" },
{ color::BLUE, "blue" },
{ color::INDIGO, "indigo" },
{ color::VIOLET, "violet" },
};
if (m != expected) {
throw std::invalid_argument("map mismatch");
}
}
......@@ -14,6 +14,7 @@ public class AllTests extends TestSuite {
mySuite.addTestSuite(RecordWithDerivingsTest.class);
mySuite.addTestSuite(CppExceptionTest.class);
mySuite.addTestSuite(ClientInterfaceTest.class);
mySuite.addTestSuite(EnumTest.class);
return mySuite;
}
......
......@@ -35,6 +35,7 @@
65BAE70C19A6C7100035F775 /* DBRecordWithDerivings.mm in Sources */ = {isa = PBXBuildFile; fileRef = 65BAE6FC19A6C7100035F775 /* DBRecordWithDerivings.mm */; };
65BAE70D19A6C7100035F775 /* DBRecordWithNestedDerivings.mm in Sources */ = {isa = PBXBuildFile; fileRef = 65BAE6FF19A6C7100035F775 /* DBRecordWithNestedDerivings.mm */; };
65BAE70E19A6C7100035F775 /* DBSetRecord.mm in Sources */ = {isa = PBXBuildFile; fileRef = 65BAE70219A6C7100035F775 /* DBSetRecord.mm */; };
A2059B6219DF7DDE006A2896 /* DBColorTranslator.mm in Sources */ = {isa = PBXBuildFile; fileRef = A2059B6019DF7DDE006A2896 /* DBColorTranslator.mm */; };
A278D45019BA33CB006FD937 /* DBTestHelpersCppProxy.mm in Sources */ = {isa = PBXBuildFile; fileRef = A278D44E19BA33CB006FD937 /* DBTestHelpersCppProxy.mm */; };
A278D45319BA3601006FD937 /* test_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A278D45219BA3601006FD937 /* test_helpers.cpp */; };
A2CB54B419BA6E6000A9E600 /* DJIError.mm in Sources */ = {isa = PBXBuildFile; fileRef = A2CB54B319BA6E6000A9E600 /* DJIError.mm */; };
......@@ -130,6 +131,10 @@
65BAE70019A6C7100035F775 /* DBSetRecord+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DBSetRecord+Private.h"; sourceTree = "<group>"; };
65BAE70119A6C7100035F775 /* DBSetRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBSetRecord.h; sourceTree = "<group>"; };
65BAE70219A6C7100035F775 /* DBSetRecord.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DBSetRecord.mm; sourceTree = "<group>"; };
A2059B5E19DF7DBA006A2896 /* color.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = color.hpp; sourceTree = "<group>"; };
A2059B5F19DF7DDE006A2896 /* DBColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBColor.h; sourceTree = "<group>"; };
A2059B6019DF7DDE006A2896 /* DBColorTranslator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DBColorTranslator.mm; sourceTree = "<group>"; };
A2059B6119DF7DDE006A2896 /* DBColorTranslator+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DBColorTranslator+Private.h"; sourceTree = "<group>"; };
A278D44C19BA33CB006FD937 /* DBTestHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBTestHelpers.h; sourceTree = "<group>"; };
A278D44D19BA33CB006FD937 /* DBTestHelpersCppProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBTestHelpersCppProxy.h; sourceTree = "<group>"; };
A278D44E19BA33CB006FD937 /* DBTestHelpersCppProxy.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DBTestHelpersCppProxy.mm; sourceTree = "<group>"; };
......@@ -251,6 +256,7 @@
65BAE6D619A6C7100035F775 /* generated-cpp */ = {
isa = PBXGroup;
children = (
A2059B5E19DF7DBA006A2896 /* color.hpp */,
A278D45119BA3428006FD937 /* test_helpers.hpp */,
65BAE6D719A6C7100035F775 /* client_interface.hpp */,
65BAE6D819A6C7100035F775 /* client_returned_record.hpp */,
......@@ -272,6 +278,9 @@
65BAE6E319A6C7100035F775 /* generated-objc */ = {
isa = PBXGroup;
children = (
A2059B5F19DF7DDE006A2896 /* DBColor.h */,
A2059B6019DF7DDE006A2896 /* DBColorTranslator.mm */,
A2059B6119DF7DDE006A2896 /* DBColorTranslator+Private.h */,
A278D44C19BA33CB006FD937 /* DBTestHelpers.h */,
A278D44D19BA33CB006FD937 /* DBTestHelpersCppProxy.h */,
A278D44E19BA33CB006FD937 /* DBTestHelpersCppProxy.mm */,
......@@ -404,6 +413,7 @@
6536CD7419A6C96C00DD7715 /* DBClientInterfaceImpl.mm in Sources */,
65BAE70A19A6C7100035F775 /* DBNestedCollection.mm in Sources */,
65BAE70E19A6C7100035F775 /* DBSetRecord.mm in Sources */,
A2059B6219DF7DDE006A2896 /* DBColorTranslator.mm in Sources */,
65BAE70D19A6C7100035F775 /* DBRecordWithNestedDerivings.mm in Sources */,
65BAE70619A6C7100035F775 /* DBClientReturnedRecord.mm in Sources */,
65BAE70719A6C7100035F775 /* DBCppExceptionCppProxy.mm in Sources */,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment