/* * 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. */ package com.google.devtools.j2objc.gen; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.devtools.j2objc.types.Import; import java.util.Collection; import java.util.List; import java.util.Set; /** * Generates segmented Objective-C header files from compilation units. In a * segmented header each type is given separate header guards and can be * included without including the other types in the file. * * @author Keith Stanger */ public class ObjectiveCSegmentedHeaderGenerator extends ObjectiveCHeaderGenerator { protected ObjectiveCSegmentedHeaderGenerator(GenerationUnit unit) { super(unit); } public static void generate(GenerationUnit unit) { new ObjectiveCSegmentedHeaderGenerator(unit).generate(); } @Override protected void generateFileHeader() { println("#include \"J2ObjC_header.h\""); newline(); printf("#pragma push_macro(\"INCLUDE_ALL_%s\")\n", varPrefix); printf("#ifdef RESTRICT_%s\n", varPrefix); printf("#define INCLUDE_ALL_%s 0\n", varPrefix); println("#else"); printf("#define INCLUDE_ALL_%s 1\n", varPrefix); println("#endif"); printf("#undef RESTRICT_%s\n", varPrefix); for (GeneratedType type : Lists.reverse(getOrderedTypes())) { printLocalIncludes(type); } pushIgnoreDeprecatedDeclarationsPragma(); pushIgnoreNullabilityCompletenessPragma(); // Print OCNI blocks Collection<String> nativeBlocks = getGenerationUnit().getNativeHeaderBlocks(); if (!nativeBlocks.isEmpty()) { // Use a normal header guard for OCNI code outside of a type declaration. printf("\n#ifndef %s_H\n", varPrefix); printf("#define %s_H\n", varPrefix); for (String code : nativeBlocks) { print(code); } printf("\n#endif // %s_H\n", varPrefix); } } /** * Given a {@link com.google.devtools.j2objc.gen.GeneratedType} * and its collected {@link com.google.devtools.j2objc.types.Import}s, * print its 'local includes'; viz., * {@code INCLUDE} directives for all supertypes that are defined in the * current segmented header. */ private void printLocalIncludes(GeneratedType type) { String typeName = type.getTypeName(); Set<Import> includes = type.getHeaderIncludes(); List<Import> localImports = Lists.newArrayList(); for (Import imp : includes) { if (isLocalType(imp.getTypeName())) { localImports.add(imp); } } if (!localImports.isEmpty()) { printf("#ifdef INCLUDE_%s\n", typeName); for (Import imp : localImports) { printf("#define INCLUDE_%s 1\n", imp.getTypeName()); } println("#endif"); } } @Override protected void generateFileFooter() { // Don't need #endif for file-level header guard. newline(); popIgnoreNullabilityCompletenessPragma(); popIgnoreDeprecatedDeclarationsPragma(); printf("#pragma pop_macro(\"INCLUDE_ALL_%s\")\n", varPrefix); } @Override protected void printTypeDeclaration(GeneratedType type) { String typeName = type.getTypeName(); String code = type.getPublicDeclarationCode(); if (code.length() == 0) { return; } newline(); printf("#if !defined (%s_) && (INCLUDE_ALL_%s || defined(INCLUDE_%s))\n", typeName, varPrefix, typeName); printf("#define %s_\n", typeName); Set<Import> forwardDeclarations = Sets.newHashSet(type.getHeaderForwardDeclarations()); for (Import imp : type.getHeaderIncludes()) { // Verify this import isn't declared in this source file. if (isLocalType(imp.getTypeName())) { continue; } newline(); printf("#define RESTRICT_%s 1\n", getVarPrefix(imp.getImportFileName())); printf("#define INCLUDE_%s 1\n", imp.getTypeName()); printf("#include \"%s\"\n", imp.getImportFileName()); forwardDeclarations.remove(imp); } printForwardDeclarations(forwardDeclarations); print(code); newline(); println("#endif"); } }